Split C++ generated code into "enums" and "parser" parts

The "enums" part contains only the enum definitions from the
xsd file. This part is lightweight and doesn't depend on libxml2.
The "parser" complements the "enums" part and depends on it.

By default both parts are generated. To generate the "enums"
part only, enable "enums_only" property in the xsdc module.
To generate the "parser" part only, enable "parser_only".
These properties are mutually exclusive.

New unit tests added to verify that the decomposition works.

Bug: 180449205
Test: atest xsdc-cpp-tests xsdc-cpp-tests-split xsdc-cpp-tests-enums
Change-Id: I89833f23cdd2ed087b3258a4bc5deb68f95b47bf
diff --git a/build/xsdc.go b/build/xsdc.go
index 22c0fc5..492d68e 100644
--- a/build/xsdc.go
+++ b/build/xsdc.go
@@ -69,7 +69,14 @@
 	// Whether has{element or atrribute} methods are set to public.
 	// It is not applied to C++, because these methods are always
 	// generated to public for C++.
-	Gen_has      *bool
+	Gen_has *bool
+	// Only generate code for enum converters. Applies to C++ only.
+	// This is useful for memory footprint reduction since it avoids
+	// depending on libxml2.
+	Enums_only *bool
+	// Only generate complementary code for XML parser. Applies to C++ only.
+	// The code being generated depends on the enum converters module.
+	Parser_only *bool
 }
 
 type xsdConfig struct {
@@ -79,13 +86,13 @@
 
 	genOutputDir android.Path
 	genOutputs_j android.WritablePath
-	genOutputs_c android.WritablePath
-	genOutputs_h android.WritablePath
+	genOutputs_c android.WritablePaths
+	genOutputs_h android.WritablePaths
 
 	docsPath android.Path
 
 	xsdConfigPath android.OptionalPath
-	genOutputs  android.Paths
+	genOutputs    android.Paths
 }
 
 var _ android.SourceFileProducer = (*xsdConfig)(nil)
@@ -112,7 +119,7 @@
 }
 
 func (module *xsdConfig) GeneratedSourceFiles() android.Paths {
-	return android.Paths{module.genOutputs_c}
+	return module.genOutputs_c.Paths()
 }
 
 func (module *xsdConfig) Srcs() android.Paths {
@@ -120,7 +127,7 @@
 }
 
 func (module *xsdConfig) GeneratedDeps() android.Paths {
-	return android.Paths{module.genOutputs_h}
+	return module.genOutputs_h.Paths()
 }
 
 func (module *xsdConfig) GeneratedHeaderDirs() android.Paths {
@@ -179,6 +186,14 @@
 		args = args + " -g "
 	}
 
+	if proptools.Bool(module.properties.Enums_only) {
+		args = args + " -e "
+	}
+
+	if proptools.Bool(module.properties.Parser_only) {
+		args = args + " -x "
+	}
+
 	module.genOutputs_j = android.PathForModuleGen(ctx, "java", filenameStem+"_xsdcgen.srcjar")
 
 	ctx.Build(pctx, android.BuildParams{
@@ -189,25 +204,41 @@
 		Output:      module.genOutputs_j,
 		Args: map[string]string{
 			"pkgName": pkgName,
-			"args": args,
+			"args":    args,
 		},
 	})
 
-	module.genOutputs_c = android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp")
-	module.genOutputs_h = android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h")
+	if proptools.Bool(module.properties.Enums_only) {
+		module.genOutputs_c = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")}
+		module.genOutputs_h = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")}
+	} else if proptools.Bool(module.properties.Parser_only) {
+		module.genOutputs_c = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp")}
+		module.genOutputs_h = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h")}
+	} else {
+		module.genOutputs_c = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp"),
+			android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")}
+		module.genOutputs_h = android.WritablePaths{
+			android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h"),
+			android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")}
+	}
 	module.genOutputDir = android.PathForModuleGen(ctx, "cpp", "include")
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:           xsdcCppRule,
-		Description:    "xsdc " + xsdFile.String(),
-		Input:          xsdFile,
-		Implicit:       module.docsPath,
-		Output:         module.genOutputs_c,
-		ImplicitOutput: module.genOutputs_h,
+		Rule:            xsdcCppRule,
+		Description:     "xsdc " + xsdFile.String(),
+		Input:           xsdFile,
+		Implicit:        module.docsPath,
+		Outputs:         module.genOutputs_c,
+		ImplicitOutputs: module.genOutputs_h,
 		Args: map[string]string{
 			"pkgName": pkgName,
 			"outDir":  android.PathForModuleGen(ctx, "cpp").String(),
-			"args": args,
+			"args":    args,
 		},
 	})
 	module.xsdConfigPath = android.ExistentPathForSource(ctx, xsdFile.String())
diff --git a/src/com/android/xsdc/CodeWriter.java b/src/com/android/xsdc/CodeWriter.java
index 1ffe801..489ccdc 100644
--- a/src/com/android/xsdc/CodeWriter.java
+++ b/src/com/android/xsdc/CodeWriter.java
@@ -24,6 +24,10 @@
     private int indent;
     private boolean startLine;
 
+    public CodeWriter() {
+        this(null);
+    }
+
     public CodeWriter(PrintWriter printWriter) {
         out = printWriter;
         indent = 0;
@@ -33,13 +37,15 @@
     private void printIndent() {
         assert startLine;
         for (int i = 0; i < indent; ++i) {
-            out.print("    ");
+            printImpl("    ");
         }
         startLine = false;
     }
 
     public void println() {
-        out.println();
+        if (out != null) {
+            out.println();
+        }
         startLine = true;
     }
 
@@ -58,13 +64,12 @@
             if (startLine && !line.isEmpty()) {
                 printIndent();
             }
-            out.print(line);
+            printImpl(line);
             if (line.endsWith("{")) {
                 ++indent;
             }
             if (i + 1 < lines.length) {
-                out.println();
-                startLine = true;
+                println();
             }
         }
     }
@@ -79,4 +84,10 @@
             out.close();
         }
     }
+
+    private void printImpl(String code) {
+        if (out != null) {
+            out.print(code);
+        }
+    }
 }
diff --git a/src/com/android/xsdc/Main.java b/src/com/android/xsdc/Main.java
index 5f786f3..caac98b 100644
--- a/src/com/android/xsdc/Main.java
+++ b/src/com/android/xsdc/Main.java
@@ -29,7 +29,9 @@
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.GnuParser;
 import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.OptionGroup;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 
@@ -75,6 +77,24 @@
                 .hasArgs(0)
                 .withDescription("Generate public hasX() method")
                 .create("g"));
+        Option genEnumsOnly = OptionBuilder
+                .withLongOpt("genEnumsOnly")
+                .hasArgs(0)
+                .withDescription("Only generate enum converters in Cpp code.")
+                .create("e");
+        options.addOption(genEnumsOnly);
+        Option genParserOnly = OptionBuilder
+                .withLongOpt("genParserOnly")
+                .hasArgs(0)
+                .withDescription("Only generate XML parser in Cpp code.")
+                .create("x");
+        options.addOption(genParserOnly);
+        // "Only generate enums" and "Only generate parser" options are mutually exclusive.
+        OptionGroup genOnlyGroup = new OptionGroup();
+        genOnlyGroup.setRequired(false);
+        genOnlyGroup.addOption(genEnumsOnly);
+        genOnlyGroup.addOption(genParserOnly);
+        options.addOptionGroup(genOnlyGroup);
 
         CommandLineParser CommandParser = new GnuParser();
         CommandLine cmd;
@@ -93,9 +113,11 @@
         boolean writer = cmd.hasOption('w');
         boolean nullability = cmd.hasOption('n');
         boolean genHas = cmd.hasOption('g');
+        boolean enumsOnly = cmd.hasOption('e');
+        boolean parserOnly = cmd.hasOption('x');
 
         if (xsdFile.length != 1 || packageName == null) {
-            System.err.println("Error: no xsd files or pacakge name");
+            System.err.println("Error: no xsd files or package name");
             help(options);
         }
 
@@ -116,8 +138,11 @@
             File includeDir = new File(Paths.get(outDir, "include").toString());
             includeDir.mkdirs();
             FileSystem fs = new FileSystem(new File(outDir));
+            int generators = enumsOnly ? CppCodeGenerator.GENERATE_ENUMS :
+                    (parserOnly ? CppCodeGenerator.GENERATE_PARSER :
+                            CppCodeGenerator.GENERATE_ENUMS | CppCodeGenerator.GENERATE_PARSER);
             CppCodeGenerator cppCodeGenerator =
-                    new CppCodeGenerator(xmlSchema, packageName, writer);
+                    new CppCodeGenerator(xmlSchema, packageName, writer, generators);
             cppCodeGenerator.print(fs);
         }
     }
diff --git a/src/com/android/xsdc/cpp/CppCodeGenerator.java b/src/com/android/xsdc/cpp/CppCodeGenerator.java
index e2a98c8..561d3f5 100644
--- a/src/com/android/xsdc/cpp/CppCodeGenerator.java
+++ b/src/com/android/xsdc/cpp/CppCodeGenerator.java
@@ -34,21 +34,28 @@
 import javax.xml.namespace.QName;
 
 public class CppCodeGenerator {
+    public static final int GENERATE_ENUMS = 1 << 0;
+    public static final int GENERATE_PARSER = 1 << 1;
+
     private XmlSchema xmlSchema;
     private String pkgName;
     private Map<String, CppSimpleType> cppSimpleTypeMap;
-    private CodeWriter cppFile;
-    private CodeWriter headerFile;
+    private CodeWriter enumsCppFile;
+    private CodeWriter enumsHeaderFile;
+    private CodeWriter parserCppFile;
+    private CodeWriter parserHeaderFile;
     private boolean hasAttr;
     private boolean writer;
+    private int generators;
 
     private static final String UNKNOWN_ENUM = "UNKNOWN";
 
-    public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer)
+    public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators)
             throws CppCodeGeneratorException {
         this.xmlSchema = xmlSchema;
         this.pkgName = pkgName;
         this.writer = writer;
+        this.generators = generators;
 
         // class naming validation
         {
@@ -95,11 +102,26 @@
 
     public void print(FileSystem fs)
             throws CppCodeGeneratorException, IOException {
-        // cpp file, headr file init
-        String cppFileName = pkgName.replace(".", "_") + ".cpp";
-        String hFileName =  pkgName.replace(".", "_") + ".h";
-        cppFile =  new CodeWriter(fs.getPrintWriter(cppFileName));
-        headerFile = new CodeWriter(fs.getPrintWriter("include/" + hFileName));
+        // cpp file, header file init
+        String fileNameStem = pkgName.replace('.', '_');
+        String enumsCppFileName = fileNameStem + "_enums.cpp";
+        String enumsHeaderFileName = fileNameStem + "_enums.h";
+        String parserCppFileName = fileNameStem + ".cpp";
+        String parserHeaderFileName = fileNameStem + ".h";
+        if ((this.generators & GENERATE_ENUMS) == GENERATE_ENUMS) {
+            enumsCppFile = new CodeWriter(fs.getPrintWriter(enumsCppFileName));
+            enumsHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + enumsHeaderFileName));
+        } else {
+            enumsCppFile = new CodeWriter();
+            enumsHeaderFile = new CodeWriter();
+        }
+        if ((this.generators & GENERATE_PARSER) == GENERATE_PARSER) {
+            parserCppFile = new CodeWriter(fs.getPrintWriter(parserCppFileName));
+            parserHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + parserHeaderFileName));
+        } else {
+            parserCppFile = new CodeWriter();
+            parserHeaderFile = new CodeWriter();
+        }
 
         boolean hasEnums = false;
         for (XsdType type : xmlSchema.getTypeMap().values()) {
@@ -110,33 +132,46 @@
             }
         }
 
-        String headerMacro = hFileName.toUpperCase().replace(".", "_");
-        headerFile.printf("#ifndef %s\n", headerMacro);
-        headerFile.printf("#define %s\n", headerMacro);
-        headerFile.printf("\n");
-        headerFile.printf("#include <array>\n");
-        headerFile.printf("#include <map>\n");
-        headerFile.printf("#include <optional>\n");
-        headerFile.printf("#include <string>\n");
-        headerFile.printf("#include <vector>\n");
+        String enumsHeaderMacro = enumsHeaderFileName.toUpperCase().replace('.', '_');
+        String parserHeaderMacro = parserHeaderFileName.toUpperCase().replace('.', '_');
+        enumsHeaderFile.printf("#ifndef %s\n", enumsHeaderMacro);
+        enumsHeaderFile.printf("#define %s\n", enumsHeaderMacro);
+        enumsHeaderFile.printf("\n");
+        enumsHeaderFile.printf("#include <array>\n");
+        enumsHeaderFile.printf("#include <string>\n");
+        enumsHeaderFile.printf("\n");
+        parserHeaderFile.printf("#ifndef %s\n", parserHeaderMacro);
+        parserHeaderFile.printf("#define %s\n", parserHeaderMacro);
+        parserHeaderFile.printf("\n");
+        parserHeaderFile.printf("#include <array>\n");
+        parserHeaderFile.printf("#include <map>\n");
+        parserHeaderFile.printf("#include <optional>\n");
+        parserHeaderFile.printf("#include <string>\n");
+        parserHeaderFile.printf("#include <vector>\n");
         if (writer) {
-            headerFile.printf("#include <iostream>\n");
+            parserHeaderFile.printf("#include <iostream>\n");
         }
-        headerFile.printf("\n");
-        headerFile.printf("#if __has_include(<libxml/parser.h>)\n");
-        headerFile.printf("#include <libxml/parser.h>\n");
-        headerFile.printf("#include <libxml/xinclude.h>\n");
-        headerFile.printf("#else\n");
-        headerFile.printf("#error Require libxml2 library. ");
-        headerFile.printf("Please add libxml2 to shared_libs or static_libs\n");
-        headerFile.printf("#endif\n");
+        parserHeaderFile.printf("\n");
+        parserHeaderFile.printf("#if __has_include(<libxml/parser.h>)\n");
+        parserHeaderFile.printf("#include <libxml/parser.h>\n");
+        parserHeaderFile.printf("#include <libxml/xinclude.h>\n");
+        parserHeaderFile.printf("#else\n");
+        parserHeaderFile.printf("#error Require libxml2 library. ");
+        parserHeaderFile.printf("Please add libxml2 to shared_libs or static_libs\n");
+        parserHeaderFile.printf("#endif\n");
         if (hasEnums) {
-            headerFile.printf("#include <xsdc/XsdcSupport.h>\n");
+            enumsHeaderFile.printf("#include <xsdc/XsdcSupport.h>\n");
+            enumsHeaderFile.printf("\n");
         }
-        headerFile.printf("\n");
+        parserHeaderFile.printf("\n");
+        parserHeaderFile.printf("#include \"%s\"\n", enumsHeaderFileName);
+        parserHeaderFile.printf("\n");
 
-        cppFile.printf("#define LOG_TAG \"%s\"\n", pkgName);
-        cppFile.printf("#include \"%s\"\n\n", hFileName);
+        enumsCppFile.printf("#include <map>\n");
+        enumsCppFile.printf("\n");
+        enumsCppFile.printf("#include \"%s\"\n\n", enumsHeaderFileName);
+        parserCppFile.printf("#define LOG_TAG \"%s\"\n", pkgName);
+        parserCppFile.printf("#include \"%s\"\n\n", parserHeaderFileName);
 
         List<String> namespace = new java.util.ArrayList<>();
         for (String token : pkgName.split("\\.")) {
@@ -147,8 +182,10 @@
                 token = "_" + token;
             }
             namespace.add(token);
-            headerFile.printf("namespace %s {\n", token);
-            cppFile.printf("namespace %s {\n", token);
+            enumsHeaderFile.printf("namespace %s {\n", token);
+            enumsCppFile.printf("namespace %s {\n", token);
+            parserHeaderFile.printf("namespace %s {\n", token);
+            parserCppFile.printf("namespace %s {\n", token);
         }
 
         printPrototype();
@@ -183,13 +220,15 @@
 
         Collections.reverse(namespace);
         for (String token : namespace) {
-            headerFile.printf("} // %s\n", token);
-            cppFile.printf("} // %s\n", token);
+            enumsHeaderFile.printf("} // %s\n", token);
+            enumsCppFile.printf("} // %s\n", token);
+            parserHeaderFile.printf("} // %s\n", token);
+            parserCppFile.printf("} // %s\n", token);
         }
 
         if (hasEnums) {
-            headerFile.printf("\n//\n// global type declarations for package\n//\n\n");
-            headerFile.printf("namespace android {\nnamespace details {\n");
+            enumsHeaderFile.printf("\n//\n// global type declarations for package\n//\n\n");
+            enumsHeaderFile.printf("namespace android {\nnamespace details {\n");
             Collections.reverse(namespace);
             for (XsdType type : xmlSchema.getTypeMap().values()) {
                 if (type instanceof XsdRestriction &&
@@ -199,82 +238,79 @@
                     printEnumValues(namespace, name, restrictionType);
                 }
             }
-            headerFile.printf("}  // namespace details\n}  // namespace android\n\n");
+            enumsHeaderFile.printf("}  // namespace details\n}  // namespace android\n\n");
         }
 
-        headerFile.printf("#endif // %s\n", headerMacro);
-        cppFile.close();
-        headerFile.close();
+        parserHeaderFile.printf("#endif // %s\n", parserHeaderMacro);
+        enumsHeaderFile.printf("#endif // %s\n", enumsHeaderMacro);
+        parserCppFile.close();
+        parserHeaderFile.close();
+        enumsCppFile.close();
+        enumsHeaderFile.close();
     }
 
     private void printEnum(String name, XsdRestriction restrictionType)
             throws CppCodeGeneratorException {
-        headerFile.printf("enum class %s {\n", name);
-        cppFile.printf("const std::map<std::string, %s> %sString {\n", name, name);
+        enumsHeaderFile.printf("enum class %s {\n", name);
+        enumsCppFile.printf("const std::map<std::string, %s> %sString {\n", name, name);
         List<XsdEnumeration> enums = restrictionType.getEnums();
 
-        headerFile.printf("%s = %d,\n", UNKNOWN_ENUM, -1);
+        enumsHeaderFile.printf("%s = %d,\n", UNKNOWN_ENUM, -1);
         for (XsdEnumeration tag : enums) {
             String value = tag.getValue();
-            headerFile.printf("%s,\n", Utils.toEnumName(value));
-            cppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name,
+            enumsHeaderFile.printf("%s,\n", Utils.toEnumName(value));
+            enumsCppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name,
                     Utils.toEnumName(value));
         }
-        headerFile.printf("};\n");
-        cppFile.printf("};\n\n");
+        enumsHeaderFile.printf("};\n");
+        enumsCppFile.printf("};\n\n");
 
-        headerFile.printf("%s stringTo%s(const std::string& value);\n",
+        enumsHeaderFile.printf("%s stringTo%s(const std::string& value);\n",
                 name, name);
-        cppFile.printf("%s stringTo%s(const std::string& value) {\n"
+        enumsCppFile.printf("%s stringTo%s(const std::string& value) {\n"
                 + "auto enumValue = %sString.find(value);\n"
                 + "return enumValue != %sString.end() ? enumValue->second : %s::%s;\n"
                 + "}\n\n", name, name, name, name, name, UNKNOWN_ENUM);
 
-        headerFile.printf("std::string toString(%s o);\n\n", name);
-        cppFile.printf("std::string toString(%s o) {\n", name);
-        cppFile.printf("switch (o) {\n");
+        enumsHeaderFile.printf("std::string toString(%s o);\n\n", name);
+        enumsCppFile.printf("std::string toString(%s o) {\n", name);
+        enumsCppFile.printf("switch (o) {\n");
         for (XsdEnumeration tag : enums) {
             String value = tag.getValue();
-            cppFile.printf("case %s::%s: return \"%s\";\n",
+            enumsCppFile.printf("case %s::%s: return \"%s\";\n",
                     name, Utils.toEnumName(value), tag.getValue());
         }
-        cppFile.printf("default: return std::to_string(static_cast<int>(o));\n}\n");
-        cppFile.printf("}\n\n");
+        enumsCppFile.printf("default: return std::to_string(static_cast<int>(o));\n}\n");
+        enumsCppFile.printf("}\n\n");
     }
 
     private void printEnumValues(List<String> namespace, String name,
             XsdRestriction restrictionType) throws CppCodeGeneratorException {
         List<XsdEnumeration> enums = restrictionType.getEnums();
         String absoluteNamespace = "::" + String.join("::", namespace);
-        headerFile.printf("template<> inline constexpr std::array<%s::%s, %d> "
+        enumsHeaderFile.printf("template<> inline constexpr std::array<%s::%s, %d> "
                 + "xsdc_enum_values<%s::%s> = {\n",
                 absoluteNamespace, name, enums.size(), absoluteNamespace, name);
         for (XsdEnumeration tag : enums) {
             String value = tag.getValue();
-            headerFile.printf("%s::%s::%s,\n", absoluteNamespace, name, Utils.toEnumName(value));
+            enumsHeaderFile.printf("%s::%s::%s,\n",
+                    absoluteNamespace, name, Utils.toEnumName(value));
         }
-        headerFile.printf("};\n");
+        enumsHeaderFile.printf("};\n");
     }
 
     private void printPrototype() throws CppCodeGeneratorException {
         for (XsdType type : xmlSchema.getTypeMap().values()) {
-            if (type instanceof XsdRestriction &&
-                ((XsdRestriction)type).getEnums() != null) {
-                String name = Utils.toClassName(type.getName());
-                headerFile.printf("enum class %s;\n", name);
-            }
-        }
-        for (XsdType type : xmlSchema.getTypeMap().values()) {
             if (type instanceof XsdComplexType) {
                 String name = Utils.toClassName(type.getName());
-                headerFile.printf("class %s;\n", name);
+                parserHeaderFile.printf("class %s;\n", name);
             }
         }
         for (XsdElement element : xmlSchema.getElementMap().values()) {
             XsdType type = element.getType();
             if (type.getRef() == null && type instanceof XsdComplexType) {
                 String name = Utils.toClassName(element.getName());
-                headerFile.printf("class %s;\n", name);
+                parserHeaderFile.printf("class %s;\n", name);
             }
         }
     }
@@ -288,12 +324,12 @@
         CppSimpleType valueType = (complexType instanceof XsdSimpleContent) ?
                 getValueType((XsdSimpleContent) complexType, false) : null;
 
-        headerFile.printf("class %s ", name);
+        parserHeaderFile.printf("class %s ", name);
 
         if (baseName != null) {
-            headerFile.printf(": public %s {\n", baseName);
+            parserHeaderFile.printf(": public %s {\n", baseName);
         } else {
-            headerFile.println("{");
+            parserHeaderFile.println("{");
         }
 
         // parse types for elements and attributes
@@ -308,11 +344,11 @@
             if (element.getRef() == null && element.getType().getRef() == null
                     && element.getType() instanceof XsdComplexType) {
                 // print inner class for anonymous types
-                headerFile.printf("public:\n");
+                parserHeaderFile.printf("public:\n");
                 String innerName = Utils.toClassName(getElementName(element));
                 XsdComplexType innerType = (XsdComplexType) element.getType();
                 printClass(innerName, nameScope + name + "::", innerType);
-                headerFile.println();
+                parserHeaderFile.println();
                 cppType = new CppComplexType(nameScope + name + "::"+ innerName);
             } else {
                 cppType = parseType(elementValue.getType(), getElementName(elementValue));
@@ -333,14 +369,14 @@
 
         // print member variables
 
-        headerFile.printf("private:\n");
+        parserHeaderFile.printf("private:\n");
         for (int i = 0; i < elementTypes.size(); ++i) {
             CppType type = elementTypes.get(i);
             XsdElement element = elements.get(i);
             XsdElement elementValue = resolveElement(element);
             String typeName = Utils.elementTypeName(type.getName(),
                     element.isMultiple() || type instanceof CppComplexType);
-            headerFile.printf("const %s %s_;\n", typeName,
+            parserHeaderFile.printf("const %s %s_;\n", typeName,
                     Utils.toVariableName(getElementName(elementValue)));
         }
         for (int i = 0; i < attributeTypes.size(); ++i) {
@@ -348,16 +384,17 @@
             XsdAttribute attribute = resolveAttribute(attributes.get(i));
             String variableName = Utils.toVariableName(attribute.getName());
             if (attribute.isRequired()) {
-                headerFile.printf("const %s %s_;\n", type.getName(), variableName);
+                parserHeaderFile.printf("const %s %s_;\n", type.getName(), variableName);
             } else {
-                headerFile.printf("const std::optional<%s> %s_;\n", type.getName(), variableName);
+                parserHeaderFile.printf("const std::optional<%s> %s_;\n",
+                        type.getName(), variableName);
             }
         }
         if (valueType != null) {
-            headerFile.printf("const std::optional<%s> _value;\n", valueType.getName());
+            parserHeaderFile.printf("const std::optional<%s> _value;\n", valueType.getName());
         }
 
-        headerFile.printf("public:\n");
+        parserHeaderFile.printf("public:\n");
         String constructorArgs = printConstructor(name, nameScope, complexType, elements,
                 attributes, baseName);
 
@@ -388,7 +425,7 @@
             printWriter(name, nameScope, complexType);
         }
 
-        headerFile.println("};\n");
+        parserHeaderFile.println("};\n");
     }
 
     private void printParser(String name, String nameScope, XsdComplexType complexType, String args)
@@ -413,51 +450,51 @@
         }
 
         String fullName = nameScope + name;
-        headerFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name));
-        cppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName);
+        parserHeaderFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name));
+        parserCppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName);
 
-        cppFile.print("std::string raw;\n");
+        parserCppFile.print("std::string raw;\n");
 
         for (int i = 0; i < allAttributes.size(); ++i) {
             CppSimpleType type = allAttributeTypes.get(i);
             XsdAttribute attribute = resolveAttribute(allAttributes.get(i));
             String variableName = Utils.toVariableName(attribute.getName());
-            cppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName());
+            parserCppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName());
             if (attribute.isRequired()) {
                 if (type.isEnum()) {
-                    cppFile.printf("%s %s = %s::%s;\n",
+                    parserCppFile.printf("%s %s = %s::%s;\n",
                             type.getName(), variableName, type.getName(), UNKNOWN_ENUM);
                 } else {
-                    cppFile.printf("%s %s{};\n", type.getName(), variableName);
+                    parserCppFile.printf("%s %s{};\n", type.getName(), variableName);
                 }
             } else {
-                cppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(),
+                parserCppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(),
                         variableName);
             }
-            cppFile.printf("if (raw != \"\") {\n");
-            cppFile.print(type.getParsingExpression());
-            cppFile.printf("%s = value;\n}\n", variableName);
+            parserCppFile.printf("if (raw != \"\") {\n");
+            parserCppFile.print(type.getParsingExpression());
+            parserCppFile.printf("%s = value;\n}\n", variableName);
         }
 
         if (baseValueType != null) {
-            cppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("
+            parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("
                     + "root->doc, root->xmlChildrenNode, 1));\n"
                     + "if (xmlValue != nullptr) {\n"
                     + "raw = reinterpret_cast<const char*>(xmlValue.get());\n");
 
-            cppFile.print(baseValueType.getParsingExpression());
-            cppFile.printf("instance.setValue(value);\n");
-            cppFile.printf("}\n");
+            parserCppFile.print(baseValueType.getParsingExpression());
+            parserCppFile.printf("instance.setValue(value);\n");
+            parserCppFile.printf("}\n");
         } else if (!allElements.isEmpty()) {
             for (int i = 0; i < allElements.size(); ++i) {
                 CppType type = allElementTypes.get(i);
                 XsdElement element = allElements.get(i);
                 XsdElement elementValue = resolveElement(element);
                 String variableName = Utils.toVariableName(getElementName(elementValue));
-                cppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(),
+                parserCppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(),
                         element.isMultiple() || type instanceof CppComplexType), variableName);
             }
-            cppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;"
+            parserCppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;"
                     + " child = child->next) {\n");
             for (int i = 0; i < allElements.size(); ++i) {
                 CppType type = allElementTypes.get(i);
@@ -465,29 +502,31 @@
                 XsdElement elementValue = resolveElement(element);
                 String variableName = Utils.toVariableName(getElementName(elementValue));
 
-                if (i != 0) cppFile.printf("} else ");
-                cppFile.print("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>");
-                cppFile.printf("(\"%s\"))) {\n", elementValue.getName());
+                if (i != 0) parserCppFile.printf("} else ");
+                parserCppFile.print("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>");
+                parserCppFile.printf("(\"%s\"))) {\n", elementValue.getName());
 
                 if (type instanceof CppSimpleType) {
-                    cppFile.print("auto xmlValue = make_xmlUnique(xmlNodeListGetString(");
-                    cppFile.print("child->doc, child->xmlChildrenNode, 1));\n");
-                    cppFile.print("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n");
-                    cppFile.print("raw = reinterpret_cast<const char*>(xmlValue.get());\n}\n");
+                    parserCppFile.print("auto xmlValue = make_xmlUnique(xmlNodeListGetString(");
+                    parserCppFile.print("child->doc, child->xmlChildrenNode, 1));\n");
+                    parserCppFile.print("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n");
+                    parserCppFile.print("raw = reinterpret_cast<const char*>(xmlValue.get());\n}");
+                    parserCppFile.print("\n");
                 }
 
-                cppFile.print(type.getParsingExpression());
+                parserCppFile.print(type.getParsingExpression());
 
                 if (element.isMultiple() || type instanceof CppComplexType) {
-                    cppFile.printf("%s.push_back(std::move(value));\n", variableName);
+                    parserCppFile.printf("%s.push_back(std::move(value));\n", variableName);
                 } else {
-                    cppFile.printf("%s = std::move(value);\n", variableName);
+                    parserCppFile.printf("%s = std::move(value);\n", variableName);
                 }
             }
-            cppFile.printf("}\n}\n");
+            parserCppFile.printf("}\n}\n");
         }
-        cppFile.printf("%s instance%s;\n", fullName, args.length() > 0 ? "(" + args + ")" : "");
-        cppFile.print("return instance;\n}\n");
+        parserCppFile.printf("%s instance%s;\n",
+                fullName, args.length() > 0 ? "(" + args + ")" : "");
+        parserCppFile.print("return instance;\n}\n");
     }
 
     private void printWriter(String name, String nameScope, XsdComplexType complexType)
@@ -512,23 +551,24 @@
         }
 
         String fullName = nameScope + name;
-        headerFile.printf("void write(std::ostream& out, const std::string& name) const;\n");
-        cppFile.printf("\nvoid %s::write(std::ostream& out, const std::string& name) const {\n",
+        parserHeaderFile.printf("void write(std::ostream& out, const std::string& name) const;\n");
+        parserCppFile.printf(
+                "\nvoid %s::write(std::ostream& out, const std::string& name) const {\n",
                 fullName);
 
-        cppFile.printf("out << printIndent() << \"<\" << name;\n");
+        parserCppFile.printf("out << printIndent() << \"<\" << name;\n");
         for (int i = 0; i < allAttributes.size(); ++i) {
             CppType type = allAttributeTypes.get(i);
             XsdAttribute attribute = resolveAttribute(allAttributes.get(i));
             String variableName = Utils.toVariableName(attribute.getName());
-            cppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
-            cppFile.printf("out << \" %s=\\\"\";\n", attribute.getName());
-            cppFile.print(type.getWritingExpression(String.format("get%s()",
+            parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
+            parserCppFile.printf("out << \" %s=\\\"\";\n", attribute.getName());
+            parserCppFile.print(type.getWritingExpression(String.format("get%s()",
                     Utils.capitalize(variableName)), attribute.getName()));
-            cppFile.printf("out << \"\\\"\";\n}\n");
+            parserCppFile.printf("out << \"\\\"\";\n}\n");
         }
-        cppFile.print("out << \">\" << std::endl;\n");
-        cppFile.print("++indentIndex;\n");
+        parserCppFile.print("out << \">\" << std::endl;\n");
+        parserCppFile.print("++indentIndex;\n");
 
         if (!allElements.isEmpty()) {
             for (int i = 0; i < allElements.size(); ++i) {
@@ -539,37 +579,38 @@
                 String variableName = Utils.toVariableName(elementName);
 
                 if (type instanceof CppComplexType || element.isMultiple()) {
-                    cppFile.printf("for (auto& value : get%s()) {\n",
+                    parserCppFile.printf("for (auto& value : get%s()) {\n",
                             Utils.capitalize(variableName));
                     if (type instanceof CppSimpleType) {
-                        cppFile.printf("out << printIndent() << \"<%s>\";\n",
+                        parserCppFile.printf("out << printIndent() << \"<%s>\";\n",
                                 elementValue.getName());
                     }
-                    cppFile.printf(type.getWritingExpression("value", elementValue.getName()));
+                    parserCppFile.printf(
+                            type.getWritingExpression("value", elementValue.getName()));
                     if (type instanceof CppSimpleType) {
-                        cppFile.printf("out << \"</%s>\" << std::endl;\n",
+                        parserCppFile.printf("out << \"</%s>\" << std::endl;\n",
                                 elementValue.getName());
                     }
-                    cppFile.printf("}\n");
+                    parserCppFile.printf("}\n");
                 } else {
-                    cppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
+                    parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
                     if (type instanceof CppSimpleType) {
-                        cppFile.printf("out << printIndent() << \"<%s>\";\n",
+                        parserCppFile.printf("out << printIndent() << \"<%s>\";\n",
                                 elementValue.getName());
                     }
-                    cppFile.print(type.getWritingExpression(String.format("get%s()",
+                    parserCppFile.print(type.getWritingExpression(String.format("get%s()",
                               Utils.capitalize(variableName)), elementValue.getName()));
                     if (type instanceof CppSimpleType) {
-                        cppFile.printf("out << \"</%s>\" << std::endl;\n",
+                        parserCppFile.printf("out << \"</%s>\" << std::endl;\n",
                                 elementValue.getName());
                     }
-                    cppFile.print("}\n");
+                    parserCppFile.print("}\n");
                 }
             }
         }
-        cppFile.print("--indentIndex;\n");
-        cppFile.printf("out << printIndent() << \"</\" << name << \">\" << std::endl;\n");
-        cppFile.printf("}\n");
+        parserCppFile.print("--indentIndex;\n");
+        parserCppFile.printf("out << printIndent() << \"</\" << name << \">\" << std::endl;\n");
+        parserCppFile.printf("}\n");
     }
 
     private void printGetter(String name, CppType type, String variableName,
@@ -577,32 +618,33 @@
         String typeName = isMultiple ? String.format("std::vector<%s>",
                 type.getName()) : type.getName();
 
-        headerFile.printf("const %s& get%s() const;\n", typeName, Utils.capitalize(variableName));
+        parserHeaderFile.printf("const %s& get%s() const;\n", typeName,
+                Utils.capitalize(variableName));
 
-        cppFile.println();
-        cppFile.printf("const %s& %s::get%s() const {\n"
+        parserCppFile.println();
+        parserCppFile.printf("const %s& %s::get%s() const {\n"
                 + "return %s;\n}\n\n",
                 typeName, name, Utils.capitalize(variableName), isMultiple || isRequired ?
                 variableName + "_" : String.format("%s_.value()", variableName));
 
-        headerFile.printf("bool has%s() const;\n", Utils.capitalize(variableName));
-        cppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName));
+        parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName));
+        parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName));
         if (isMultiple) {
-            cppFile.printf("return !(%s_.empty());\n}\n", variableName);
+            parserCppFile.printf("return !(%s_.empty());\n}\n", variableName);
         } else if (isRequired){
-            cppFile.print("return true;\n}\n");
+            parserCppFile.print("return true;\n}\n");
         } else {
-            cppFile.printf("return %s_.has_value();\n}\n", variableName);
+            parserCppFile.printf("return %s_.has_value();\n}\n", variableName);
         }
 
         if (isMultiple || isMultipleType) {
             String elementTypeName = type instanceof CppComplexType ? type.getName() :
                     ((CppSimpleType)type).getTypeName();
             if (elementTypeName.equals("bool")) {
-                headerFile.printf("%s getFirst%s() const;\n",
+                parserHeaderFile.printf("%s getFirst%s() const;\n",
                         elementTypeName, Utils.capitalize(variableName));
-                cppFile.println();
-                cppFile.printf("%s %s::getFirst%s() const {\n"
+                parserCppFile.println();
+                parserCppFile.printf("%s %s::getFirst%s() const {\n"
                         + "if (%s_%sempty()) {\n"
                         + "return false;\n"
                         + "}\n"
@@ -613,10 +655,10 @@
                         isMultiple ? String.format("%s_[0]", variableName) :
                         String.format("%s_.value()[0]", variableName));
             } else {
-                headerFile.printf("const %s* getFirst%s() const;\n",
+                parserHeaderFile.printf("const %s* getFirst%s() const;\n",
                         elementTypeName, Utils.capitalize(variableName));
-                cppFile.println();
-                cppFile.printf("const %s* %s::getFirst%s() const {\n"
+                parserCppFile.println();
+                parserCppFile.printf("const %s* %s::getFirst%s() const {\n"
                         + "if (%s_%sempty()) {\n"
                         + "return nullptr;\n"
                         + "}\n"
@@ -692,17 +734,17 @@
         if (constructorArgsString.length() > 0) {
             constructorArgsString = constructorArgsString.substring(2);
         }
-        headerFile.printf("%s(%s);\n", name, constructorArgsString);
-        cppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString);
+        parserHeaderFile.printf("%s(%s);\n", name, constructorArgsString);
+        parserCppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString);
 
         String parentArgsString = parentArgs.toString();
         if (parentArgsString.length() > 0) {
             parentArgsString = parentArgsString.substring(2);
-            cppFile.printf("%s(%s)", baseName, parentArgsString);
+            parserCppFile.printf("%s(%s)", baseName, parentArgsString);
         } else {
             constructorString = constructorString.substring(2);
         }
-        cppFile.printf("%s {\n}\n", constructorString);
+        parserCppFile.printf("%s {\n}\n", constructorString);
 
         String argsString = args.toString();
         if (argsString.length() > 0) {
@@ -712,7 +754,7 @@
     }
 
     private void printXmlParser() throws CppCodeGeneratorException {
-        cppFile.printf("template <class T>\n"
+        parserCppFile.printf("template <class T>\n"
                 + "constexpr void (*xmlDeleter)(T* t);\n"
                 + "template <>\nconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;\n"
                 + "template <>\nauto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };\n\n"
@@ -723,7 +765,7 @@
                 + "}\n\n");
 
         if (hasAttr) {
-            cppFile.printf("static std::string getXmlAttribute"
+            parserCppFile.printf("static std::string getXmlAttribute"
                     + "(const xmlNode *cur, const char *attribute) {\n"
                     + "auto xmlValue = make_xmlUnique(xmlGetProp(cur, "
                     + "reinterpret_cast<const xmlChar*>(attribute)));\n"
@@ -745,11 +787,11 @@
             String typeName = cppType instanceof CppSimpleType ? cppType.getName() :
                     Utils.toClassName(cppType.getName());
 
-            headerFile.printf("std::optional<%s> read%s(const char* configFile);\n\n",
+            parserHeaderFile.printf("std::optional<%s> read%s(const char* configFile);\n\n",
                     typeName, isMultiRootElement ? Utils.capitalize(typeName) : "");
-            cppFile.printf("std::optional<%s> read%s(const char* configFile) {\n",
+            parserCppFile.printf("std::optional<%s> read%s(const char* configFile) {\n",
                     typeName, isMultiRootElement ? Utils.capitalize(typeName) : "");
-            cppFile.printf("auto doc = make_xmlUnique(xmlParseFile(configFile));\n"
+            parserCppFile.printf("auto doc = make_xmlUnique(xmlParseFile(configFile));\n"
                     + "if (doc == nullptr) {\n"
                     + "return std::nullopt;\n"
                     + "}\n"
@@ -765,14 +807,14 @@
                     elementName);
 
             if (cppType instanceof CppSimpleType) {
-                cppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n",
+                parserCppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n",
                         elementName, elementName);
             } else {
-                cppFile.printf(cppType.getParsingExpression());
+                parserCppFile.printf(cppType.getParsingExpression());
             }
-            cppFile.printf("return value;\n}\n");
-            cppFile.printf("return std::nullopt;\n");
-            cppFile.printf("}\n\n");
+            parserCppFile.printf("return value;\n}\n");
+            parserCppFile.printf("return std::nullopt;\n");
+            parserCppFile.printf("}\n\n");
         }
     }
 
@@ -783,17 +825,18 @@
             String VariableName = Utils.toVariableName(elementName);
             String typeName = cppType instanceof CppSimpleType ? cppType.getName() :
                     Utils.toClassName(cppType.getName());
-            headerFile.printf("void write(std::ostream& out, %s& %s);\n\n",
+            parserHeaderFile.printf("void write(std::ostream& out, %s& %s);\n\n",
                     typeName, VariableName);
-            cppFile.printf("void write(std::ostream& out, %s& %s) {\n",
+            parserCppFile.printf("void write(std::ostream& out, %s& %s) {\n",
                     typeName, VariableName);
 
-            cppFile.print("out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n");
-            cppFile.printf("%s.write(out, \"%s\");\n", VariableName, elementName);
-            cppFile.printf("}\n\n");
+            parserCppFile.print(
+                    "out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n");
+            parserCppFile.printf("%s.write(out, \"%s\");\n", VariableName, elementName);
+            parserCppFile.printf("}\n\n");
         }
 
-        cppFile.print("static int indentIndex = 0;\n"
+        parserCppFile.print("static int indentIndex = 0;\n"
                 + "std::string printIndent() {\n"
                 + "std::string s = \"\";\n"
                 + "for (int index = 0; index < indentIndex; ++index) {\n"
diff --git a/tests/Android.bp b/tests/Android.bp
index d49369b..ab44220 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -32,6 +32,8 @@
 cc_test_host {
     name: "xsdc-cpp-tests",
     srcs: [
+        "simple_type.cpp",
+        "tests.cpp",
         "main.cpp",
     ],
     test_options: {
@@ -67,3 +69,56 @@
     data: ["resources/*.xml"],
     test_suites: ["general-tests"],
 }
+
+// These tests verify that enums-only and parser-only
+// modules can be combined later.
+cc_test_host {
+    name: "xsdc-cpp-tests-split",
+    srcs: [
+        "simple_type.cpp",
+        "main.cpp",
+    ],
+    test_options: {
+        unit_test: true,
+    },
+    generated_sources: [
+        "xsdc_simple_type_tests_enums",
+        "xsdc_simple_type_tests_parser",
+    ],
+    generated_headers: [
+        "xsdc_simple_type_tests_enums",
+        "xsdc_simple_type_tests_parser",
+    ],
+    header_libs: ["libxsdc-utils"],
+    shared_libs: [
+        "libbase",
+        "libxml2",
+    ],
+    data: ["resources/*.xml"],
+    test_suites: ["general-tests"],
+}
+
+// These tests verify that enums-only module can be used on
+// its own and it does not depend on libxml2.
+cc_test_host {
+    name: "xsdc-cpp-tests-enums",
+    srcs: [
+        "simple_type_enumsonly.cpp",
+        "main.cpp",
+    ],
+    test_options: {
+        unit_test: true,
+    },
+    generated_sources: [
+        "xsdc_simple_type_tests_enums",
+    ],
+    generated_headers: [
+        "xsdc_simple_type_tests_enums",
+    ],
+    header_libs: ["libxsdc-utils"],
+    shared_libs: [
+        "libbase",
+    ],
+    data: ["resources/*.xml"],
+    test_suites: ["general-tests"],
+}
diff --git a/tests/main.cpp b/tests/main.cpp
index 4dbf2d0..5e91e2d 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,311 +14,7 @@
  * limitations under the License.
  */
 
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <optional>
-
-#include <android-base/file.h>
 #include <gtest/gtest.h>
-#include "nested_type.h"
-#include "purchase_simple.h"
-#include "simple_complex_content.h"
-
-#include "predefined_types.h"
-#include "reference.h"
-#include "simple_type.h"
-#include "attr_group_simple.h"
-#include "group.h"
-
-using namespace std;
-using ::android::base::GetExecutableDirectory;
-
-class XmlTest : public ::testing::Test {
-public:
-    virtual void SetUp() override {
-    }
-    virtual void TearDown() override {
-    }
-    std::string Resource(const std::string& filename) {
-      return GetExecutableDirectory() + "/resources/" + filename;
-    }
-};
-
-TEST_F(XmlTest, Simpletype) {
-  using namespace simple::type;
-  for (const auto v : android::xsdc_enum_range<EnumType>()) {
-    EXPECT_NE(v, EnumType::UNKNOWN);
-    EXPECT_EQ(stringToEnumType(toString(v)), v);
-  }
-
-  string file_name = Resource("simple_type.xml");
-  SimpleTypes simple = *readSimpleTypes(file_name.c_str());
-
-  for (int i = 0; i < simple.getListInt().size(); ++i) {
-    EXPECT_EQ(simple.getListInt()[i], i + 1);
-  }
-  EXPECT_EQ(*simple.getFirstUnionTest(), "100");
-  EXPECT_EQ(simple.getYesOrNo()[0], EnumType::YES);
-  EXPECT_EQ(simple.getYesOrNo()[1], EnumType::EMPTY);
-  ofstream out("old_simple_type.xml");
-  write(out, simple);
-  SimpleTypes simple2 = *readSimpleTypes("old_simple_type.xml");
-  for (int i = 0; i < simple.getListInt().size(); ++i) {
-    EXPECT_EQ(simple.getListInt()[i], simple2.getListInt()[i]);
-  }
-  EXPECT_EQ(*simple.getFirstUnionTest(), *simple2.getFirstUnionTest());
-  EXPECT_EQ(simple.getYesOrNo()[0], simple2.getYesOrNo()[0]);
-  EXPECT_EQ(simple.getYesOrNo()[1], simple2.getYesOrNo()[1]);
-}
-
-TEST_F(XmlTest, Predefinedtypes) {
-  using namespace predefined::types;
-  Types type = *read(Resource("predefined_types.xml").c_str());
-
-  StringTypes stringTypes = *type.getFirstStringTypes();
-  DateTypes dateTypes = *type.getFirstDateTypes();
-  NumericTypes numericTypes = *type.getFirstNumericTypes();
-  MiscTypes miscTypes = *type.getFirstMiscTypes();
-  ListPrimitiveTypes listPrimitiveTypes = *type.getFirstListPrimitiveTypes();
-
-  EXPECT_EQ(stringTypes.getString(), "abcd");
-  EXPECT_EQ(stringTypes.getToken(), "abcd");
-  EXPECT_EQ(stringTypes.getNormalizedString(), "abcd");
-  EXPECT_EQ(stringTypes.getLanguage(), "abcd");
-  EXPECT_EQ(stringTypes.getEntity(), "abcd");
-  EXPECT_EQ(stringTypes.getEntities()[0], "a");
-  EXPECT_EQ(stringTypes.getEntities()[1], "b");
-  EXPECT_EQ(stringTypes.getEntities()[2], "c");
-  EXPECT_EQ(stringTypes.getEntities()[3], "d");
-  EXPECT_EQ(stringTypes.getId(), "abcd");
-  EXPECT_EQ(stringTypes.getName(), "abcd");
-  EXPECT_EQ(stringTypes.getNcname(), "abcd");
-  EXPECT_EQ(stringTypes.getNmtoken(), "abcd");
-  EXPECT_EQ(stringTypes.getNmtokens()[0], "a");
-  EXPECT_EQ(stringTypes.getNmtokens()[1], "b");
-  EXPECT_EQ(stringTypes.getNmtokens()[2], "c");
-  EXPECT_EQ(stringTypes.getNmtokens()[3], "d");
-
-
-  EXPECT_EQ(dateTypes.getDate(), "2018-06-18");
-  EXPECT_EQ(dateTypes.getDateTime(), "2018-06-18T21:32:52");
-  EXPECT_EQ(dateTypes.getDuration(), "P3M");
-  EXPECT_EQ(dateTypes.getGDay(), "---18");
-  EXPECT_EQ(dateTypes.getGMonth(), "--06");
-  EXPECT_EQ(dateTypes.getGMonthDay(), "--06-18");
-  EXPECT_EQ(dateTypes.getGYear(), "2018");
-  EXPECT_EQ(dateTypes.getGYearMonth(), "2018-06");
-  EXPECT_EQ(dateTypes.getTime(), "21:32:52");
-
-  EXPECT_EQ(numericTypes.getDecimal(), 1234.57);
-  EXPECT_EQ(numericTypes.getInteger(), 1234567890123456789);
-  EXPECT_EQ(numericTypes.get_long(), 9223372036854775807);
-  EXPECT_EQ(numericTypes.get_int(), 2147483647);
-  EXPECT_EQ(numericTypes.get_short(), 32767);
-  EXPECT_EQ((int)numericTypes.getByte(), 127);
-  EXPECT_EQ(numericTypes.getNegativeInteger(), -1234);
-  EXPECT_EQ(numericTypes.getNonNegativeInteger(), 1234);
-  EXPECT_EQ(numericTypes.getPositiveInteger(), 1234);
-  EXPECT_EQ(numericTypes.getNonPositiveInteger(), -1234);
-  EXPECT_EQ(numericTypes.getUnsignedLong(), 1234);
-  EXPECT_EQ(numericTypes.getUnsignedInt(), 1234);
-  EXPECT_EQ(numericTypes.getUnsignedShort(), 1234);
-  EXPECT_EQ((int)(numericTypes.getUnsignedByte()), 255);
-
-  EXPECT_EQ(miscTypes.get_double(), 1234.57);
-  EXPECT_EQ(miscTypes.getAnyURI(), "https://www.google.com");
-  EXPECT_EQ(miscTypes.getBase64Binary(), "Z29vZ2xl");
-  EXPECT_TRUE(miscTypes.getBoolean());
-  EXPECT_EQ(miscTypes.getHexBinary(), "016a75cb56d7e7");
-  EXPECT_EQ(miscTypes.getQName(), "abcd");
-  EXPECT_EQ(miscTypes.getIDREF(), "abcd");
-  EXPECT_EQ(miscTypes.getIDREFS()[0], "abcd");
-  EXPECT_EQ(miscTypes.getIDREFS()[1], "abcd");
-  EXPECT_EQ(miscTypes.getAnyType(), "abcd");
-
-  EXPECT_EQ(listPrimitiveTypes.getListInt()[0], -2147483648);
-  EXPECT_EQ(listPrimitiveTypes.getListInt()[1], 2147483647);
-  EXPECT_EQ(listPrimitiveTypes.getListShort()[0], -32768);
-  EXPECT_EQ(listPrimitiveTypes.getListShort()[1], 32767);
-  EXPECT_EQ((int)listPrimitiveTypes.getListByte()[0], -128);
-  EXPECT_EQ((int)listPrimitiveTypes.getListByte()[1], 127);
-  EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], 1234.56);
-  EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], 5678.12);
-  EXPECT_TRUE(listPrimitiveTypes.getListBoolean()[0]);
-  EXPECT_FALSE(listPrimitiveTypes.getListBoolean()[1]);
-
-  ofstream out("old_predefined_types.xml");
-  write(out, type);
-  Types type2 = *read("old_predefined_types.xml");
-
-  NumericTypes numericTypes2 = *type.getFirstNumericTypes();
-  ListPrimitiveTypes listPrimitiveTypes2 = *type.getFirstListPrimitiveTypes();
-
-  EXPECT_EQ(numericTypes.getDecimal(), numericTypes2.getDecimal());
-  EXPECT_EQ(numericTypes.getInteger(), numericTypes2.getInteger());
-  EXPECT_EQ(numericTypes.get_long(), numericTypes2.get_long());
-  EXPECT_EQ(numericTypes.get_int(), numericTypes2.get_int());
-  EXPECT_EQ(numericTypes.get_short(), numericTypes2.get_short());
-  EXPECT_EQ(numericTypes.getByte(), numericTypes2.getByte());
-  EXPECT_EQ(numericTypes.getNegativeInteger(), numericTypes2.getNegativeInteger());
-  EXPECT_EQ(numericTypes.getNonNegativeInteger(), numericTypes2.getNonNegativeInteger());
-  EXPECT_EQ(numericTypes.getPositiveInteger(), numericTypes2.getPositiveInteger());
-  EXPECT_EQ(numericTypes.getNonPositiveInteger(), numericTypes2.getNonPositiveInteger());
-  EXPECT_EQ(numericTypes.getUnsignedLong(), numericTypes2.getUnsignedLong());
-  EXPECT_EQ(numericTypes.getUnsignedInt(), numericTypes2.getUnsignedInt());
-  EXPECT_EQ(numericTypes.getUnsignedShort(), numericTypes2.getUnsignedShort());
-  EXPECT_EQ((numericTypes.getUnsignedByte()), numericTypes2.getUnsignedByte());
-
-  EXPECT_EQ(listPrimitiveTypes.getListInt()[0], listPrimitiveTypes2.getListInt()[0]);
-  EXPECT_EQ(listPrimitiveTypes.getListInt()[1], listPrimitiveTypes2.getListInt()[1]);
-  EXPECT_EQ(listPrimitiveTypes.getListShort()[0], listPrimitiveTypes2.getListShort()[0]);
-  EXPECT_EQ(listPrimitiveTypes.getListShort()[1], listPrimitiveTypes2.getListShort()[1]);
-  EXPECT_EQ(listPrimitiveTypes.getListByte()[0], listPrimitiveTypes2.getListByte()[0]);
-  EXPECT_EQ(listPrimitiveTypes.getListByte()[1], listPrimitiveTypes2.getListByte()[1]);
-  EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], listPrimitiveTypes2.getListDouble()[0]);
-  EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], listPrimitiveTypes2.getListDouble()[1]);
-  EXPECT_EQ(listPrimitiveTypes.getListBoolean()[0], listPrimitiveTypes2.getListBoolean()[0]);
-  EXPECT_EQ(listPrimitiveTypes.getListBoolean()[1], listPrimitiveTypes2.getListBoolean()[1]);
-}
-
-TEST_F(XmlTest, Nestedtype) {
-  using namespace nested::type;
-  Employee employee = *read(Resource("nested_type.xml").c_str());
-
-  Employee::Address address = *employee.getFirstAddress();
-  Employee::Address::Extra extra = *address.getFirstExtra();
-
-  EXPECT_EQ((int)employee.getId(), 1);
-  EXPECT_EQ(employee.getName(), "Peter");
-  EXPECT_EQ(address.getCountry(), "US");
-  EXPECT_EQ(address.getState(), "Mountain View");
-  EXPECT_EQ(address.getZip(), 3342);
-  EXPECT_EQ(extra.getLine1(), "Donga 303-111");
-  EXPECT_EQ(extra.getLine2(), "Good Street");
-
-  ofstream out("old_nested_type.xml");
-  write(out, employee);
-}
-
-TEST_F(XmlTest, Purchasesimple) {
-  using namespace purchase::simple;
-  PurchaseOrderType orderType = *read(Resource("purchase_simple.xml").c_str());
-
-  EXPECT_EQ(orderType.getOrderDate(), "1900-01-01");
-
-  EXPECT_EQ(orderType.getShipTo()[0].getName(), "name1");
-  EXPECT_EQ(orderType.getShipTo()[0].getStreet(), "street1");
-  EXPECT_EQ(orderType.getShipTo()[0].getCity(), "city1");
-  EXPECT_EQ(orderType.getShipTo()[0].getState(), "state1");
-  EXPECT_EQ(orderType.getShipTo()[0].getZip(), 1);
-  EXPECT_EQ(orderType.getShipTo()[0].getCountry(), "US");
-  EXPECT_EQ(orderType.getShipTo()[1].getName(), "name2");
-  EXPECT_EQ(orderType.getShipTo()[1].getStreet(), "street2");
-  EXPECT_EQ(orderType.getShipTo()[1].getCity(), "city2");
-  EXPECT_EQ(orderType.getShipTo()[1].getState(), "state2");
-  EXPECT_EQ(orderType.getShipTo()[1].getZip(), -7922816251426433759);
-  EXPECT_EQ(orderType.getShipTo()[1].getCountry(), "US");
-
-  EXPECT_EQ(orderType.getBillTo()[0].getName(), "billName");
-  EXPECT_EQ(orderType.getBillTo()[0].getStreet(), "billStreet");
-  EXPECT_EQ(orderType.getBillTo()[0].getCity(), "billCity");
-  EXPECT_EQ(orderType.getBillTo()[0].getState(), "billState");
-  EXPECT_EQ(orderType.getBillTo()[0].getZip(), 1);
-  EXPECT_EQ(orderType.getBillTo()[0].getCountry(), "US");
-
-  ofstream out("old_purchase_simple.xml");
-  write(out, orderType);
-
-  PurchaseOrderType orderType2 = *read("old_purchase_simple.xml");
-
-  EXPECT_EQ(orderType.getOrderDate(), orderType2.getOrderDate());
-
-  EXPECT_EQ(orderType.getShipTo()[0].getName(), orderType2.getShipTo()[0].getName());
-  EXPECT_EQ(orderType.getShipTo()[0].getStreet(), orderType2.getShipTo()[0].getStreet());
-  EXPECT_EQ(orderType.getShipTo()[0].getCity(), orderType2.getShipTo()[0].getCity());
-  EXPECT_EQ(orderType.getShipTo()[0].getState(), orderType2.getShipTo()[0].getState());
-  EXPECT_EQ(orderType.getShipTo()[0].getZip(), orderType2.getShipTo()[0].getZip());
-  EXPECT_EQ(orderType.getShipTo()[0].getCountry(), orderType2.getShipTo()[0].getCountry());
-  EXPECT_EQ(orderType.getShipTo()[1].getName(), orderType2.getShipTo()[1].getName());
-  EXPECT_EQ(orderType.getShipTo()[1].getStreet(), orderType2.getShipTo()[1].getStreet());
-  EXPECT_EQ(orderType.getShipTo()[1].getCity(), orderType2.getShipTo()[1].getCity());
-  EXPECT_EQ(orderType.getShipTo()[1].getState(), orderType2.getShipTo()[1].getState());
-  EXPECT_EQ(orderType.getShipTo()[1].getZip(), orderType2.getShipTo()[1].getZip());
-  EXPECT_EQ(orderType.getShipTo()[1].getCountry(), orderType2.getShipTo()[1].getCountry());
-
-  EXPECT_EQ(orderType.getBillTo()[0].getName(), orderType2.getBillTo()[0].getName());
-  EXPECT_EQ(orderType.getBillTo()[0].getStreet(), orderType2.getBillTo()[0].getStreet());
-  EXPECT_EQ(orderType.getBillTo()[0].getCity(), orderType2.getBillTo()[0].getCity());
-  EXPECT_EQ(orderType.getBillTo()[0].getState(), orderType2.getBillTo()[0].getState());
-  EXPECT_EQ(orderType.getBillTo()[0].getZip(), orderType2.getBillTo()[0].getZip());
-  EXPECT_EQ(orderType.getBillTo()[0].getCountry(), orderType2.getBillTo()[0].getCountry());
-}
-
-TEST_F(XmlTest, Reference) {
-  using namespace reference;
-  Class _class = *read(Resource("reference.xml").c_str());
-
-  EXPECT_EQ(_class.getStudent()[0], "Sam");
-  EXPECT_EQ(_class.getStudent()[1], "Paul");
-  EXPECT_EQ(_class.getStudent()[2], "Peter");
-
-  ofstream out("old_reference.xml");
-  write(out, _class);
-}
-
-TEST_F(XmlTest, Simplecomplexcontent) {
-  using namespace simple::complex::content;
-  Person person = *readPerson(Resource("simple_complex_content.xml").c_str());
-  USAddressP uSAddressP = *person.getFirstUSAddressP();
-  KRAddress kRAddress = *person.getFirstKRAddress();
-  SubAddress subAddress = *person.getFirstSubAddress();
-
-  EXPECT_EQ(person.getName(), "Petr");
-
-  EXPECT_EQ(uSAddressP.getName(), "404");
-  EXPECT_EQ(uSAddressP.getStreet(), "street fighter");
-  EXPECT_EQ(uSAddressP.getCity(), "New York");
-  EXPECT_EQ(uSAddressP.getState(), "Washington");
-  EXPECT_EQ(uSAddressP.getZipcode(), 323232318329852);
-
-  EXPECT_EQ(kRAddress.getName(), "Donga Studio");
-  EXPECT_EQ(kRAddress.getStreet(), "Nokdu Street");
-  EXPECT_EQ(kRAddress.getCity(), "Seoul");
-
-  EXPECT_EQ(subAddress.getChoice1_optional(), "Temp");
-
-  ofstream out("old_simple_complex_content.xml");
-  write(out, person);
-}
-
-TEST_F(XmlTest, Attrgroupsimple) {
-  using namespace attr::group::simple;
-  Student student = *read(Resource("attr_group_simple.xml").c_str());
-
-  EXPECT_EQ(student.getName(), "Jun");
-  EXPECT_EQ(student.getCity(), "Mountain View");
-  EXPECT_EQ(student.getState(), "CA");
-  EXPECT_EQ(student.getRoad(), "Street 101");
-  EXPECT_EQ(student.getList()[0], 1);
-  EXPECT_EQ(student.getList()[1], 2);
-  EXPECT_EQ(student.getList()[2], 3);
-
-  ofstream out("old_attr_group_simple.xml");
-  write(out, student);
-}
-
-TEST_F(XmlTest, Group) {
-  using namespace group;
-  Student student = *read(Resource("group.xml").c_str());
-
-  EXPECT_EQ(student.getCity(), "Mountain View");
-  EXPECT_EQ(student.getState(), "CA");
-  EXPECT_EQ(student.getRoad(), "Street 101");
-
-  ofstream out("old_group.xml");
-  write(out, student);
-}
 
 int main(int argc, char **argv) {
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/tests/resources/simple_type/Android.bp b/tests/resources/simple_type/Android.bp
index 9bf2a52..b6a681d 100644
--- a/tests/resources/simple_type/Android.bp
+++ b/tests/resources/simple_type/Android.bp
@@ -9,3 +9,19 @@
     package_name: "simple.type",
     gen_writer: true,
 }
+
+xsd_config {
+    name: "xsdc_simple_type_tests_enums",
+    srcs: ["simple_type.xsd"],
+    package_name: "simple.type",
+    enums_only: true,
+    gen_writer: true,
+}
+
+xsd_config {
+    name: "xsdc_simple_type_tests_parser",
+    srcs: ["simple_type.xsd"],
+    package_name: "simple.type",
+    parser_only: true,
+    gen_writer: true,
+}
diff --git a/tests/simple_type.cpp b/tests/simple_type.cpp
new file mode 100644
index 0000000..5162c6d
--- /dev/null
+++ b/tests/simple_type.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <android-base/macros.h>
+
+#include "simple_type.h"
+#include "xmltest.h"
+
+using namespace std;
+
+TEST_F(XmlTest, Simpletype) {
+  using namespace simple::type;
+  for (const auto v : android::xsdc_enum_range<EnumType>()) {
+    EXPECT_NE(v, EnumType::UNKNOWN);
+    EXPECT_EQ(stringToEnumType(toString(v)), v);
+  }
+
+  string file_name = Resource("simple_type.xml");
+  SimpleTypes simple = *readSimpleTypes(file_name.c_str());
+
+  for (int i = 0; i < simple.getListInt().size(); ++i) {
+    EXPECT_EQ(simple.getListInt()[i], i + 1);
+  }
+  EXPECT_EQ(*simple.getFirstUnionTest(), "100");
+  EXPECT_EQ(simple.getYesOrNo()[0], EnumType::YES);
+  EXPECT_EQ(simple.getYesOrNo()[1], EnumType::EMPTY);
+  ofstream out("old_simple_type.xml");
+  write(out, simple);
+  SimpleTypes simple2 = *readSimpleTypes("old_simple_type.xml");
+  for (int i = 0; i < simple.getListInt().size(); ++i) {
+    EXPECT_EQ(simple.getListInt()[i], simple2.getListInt()[i]);
+  }
+  EXPECT_EQ(*simple.getFirstUnionTest(), *simple2.getFirstUnionTest());
+  EXPECT_EQ(simple.getYesOrNo()[0], simple2.getYesOrNo()[0]);
+  EXPECT_EQ(simple.getYesOrNo()[1], simple2.getYesOrNo()[1]);
+}
diff --git a/tests/simple_type_enumsonly.cpp b/tests/simple_type_enumsonly.cpp
new file mode 100644
index 0000000..b083a6c
--- /dev/null
+++ b/tests/simple_type_enumsonly.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/macros.h>
+
+#include "simple_type_enums.h"
+#include "xmltest.h"
+
+TEST_F(XmlTest, SimpletypeEnumsOnly) {
+  using namespace simple::type;
+  for (const auto v : android::xsdc_enum_range<EnumType>()) {
+    EXPECT_NE(v, EnumType::UNKNOWN);
+    EXPECT_EQ(stringToEnumType(toString(v)), v);
+  }
+}
diff --git a/tests/tests.cpp b/tests/tests.cpp
new file mode 100644
index 0000000..c143f4e
--- /dev/null
+++ b/tests/tests.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <optional>
+
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+#include "nested_type.h"
+#include "purchase_simple.h"
+#include "simple_complex_content.h"
+
+#include "predefined_types.h"
+#include "reference.h"
+#include "attr_group_simple.h"
+#include "group.h"
+#include "xmltest.h"
+
+using namespace std;
+
+TEST_F(XmlTest, Predefinedtypes) {
+  using namespace predefined::types;
+  Types type = *read(Resource("predefined_types.xml").c_str());
+
+  StringTypes stringTypes = *type.getFirstStringTypes();
+  DateTypes dateTypes = *type.getFirstDateTypes();
+  NumericTypes numericTypes = *type.getFirstNumericTypes();
+  MiscTypes miscTypes = *type.getFirstMiscTypes();
+  ListPrimitiveTypes listPrimitiveTypes = *type.getFirstListPrimitiveTypes();
+
+  EXPECT_EQ(stringTypes.getString(), "abcd");
+  EXPECT_EQ(stringTypes.getToken(), "abcd");
+  EXPECT_EQ(stringTypes.getNormalizedString(), "abcd");
+  EXPECT_EQ(stringTypes.getLanguage(), "abcd");
+  EXPECT_EQ(stringTypes.getEntity(), "abcd");
+  EXPECT_EQ(stringTypes.getEntities()[0], "a");
+  EXPECT_EQ(stringTypes.getEntities()[1], "b");
+  EXPECT_EQ(stringTypes.getEntities()[2], "c");
+  EXPECT_EQ(stringTypes.getEntities()[3], "d");
+  EXPECT_EQ(stringTypes.getId(), "abcd");
+  EXPECT_EQ(stringTypes.getName(), "abcd");
+  EXPECT_EQ(stringTypes.getNcname(), "abcd");
+  EXPECT_EQ(stringTypes.getNmtoken(), "abcd");
+  EXPECT_EQ(stringTypes.getNmtokens()[0], "a");
+  EXPECT_EQ(stringTypes.getNmtokens()[1], "b");
+  EXPECT_EQ(stringTypes.getNmtokens()[2], "c");
+  EXPECT_EQ(stringTypes.getNmtokens()[3], "d");
+
+
+  EXPECT_EQ(dateTypes.getDate(), "2018-06-18");
+  EXPECT_EQ(dateTypes.getDateTime(), "2018-06-18T21:32:52");
+  EXPECT_EQ(dateTypes.getDuration(), "P3M");
+  EXPECT_EQ(dateTypes.getGDay(), "---18");
+  EXPECT_EQ(dateTypes.getGMonth(), "--06");
+  EXPECT_EQ(dateTypes.getGMonthDay(), "--06-18");
+  EXPECT_EQ(dateTypes.getGYear(), "2018");
+  EXPECT_EQ(dateTypes.getGYearMonth(), "2018-06");
+  EXPECT_EQ(dateTypes.getTime(), "21:32:52");
+
+  EXPECT_EQ(numericTypes.getDecimal(), 1234.57);
+  EXPECT_EQ(numericTypes.getInteger(), 1234567890123456789);
+  EXPECT_EQ(numericTypes.get_long(), 9223372036854775807);
+  EXPECT_EQ(numericTypes.get_int(), 2147483647);
+  EXPECT_EQ(numericTypes.get_short(), 32767);
+  EXPECT_EQ((int)numericTypes.getByte(), 127);
+  EXPECT_EQ(numericTypes.getNegativeInteger(), -1234);
+  EXPECT_EQ(numericTypes.getNonNegativeInteger(), 1234);
+  EXPECT_EQ(numericTypes.getPositiveInteger(), 1234);
+  EXPECT_EQ(numericTypes.getNonPositiveInteger(), -1234);
+  EXPECT_EQ(numericTypes.getUnsignedLong(), 1234);
+  EXPECT_EQ(numericTypes.getUnsignedInt(), 1234);
+  EXPECT_EQ(numericTypes.getUnsignedShort(), 1234);
+  EXPECT_EQ((int)(numericTypes.getUnsignedByte()), 255);
+
+  EXPECT_EQ(miscTypes.get_double(), 1234.57);
+  EXPECT_EQ(miscTypes.getAnyURI(), "https://www.google.com");
+  EXPECT_EQ(miscTypes.getBase64Binary(), "Z29vZ2xl");
+  EXPECT_TRUE(miscTypes.getBoolean());
+  EXPECT_EQ(miscTypes.getHexBinary(), "016a75cb56d7e7");
+  EXPECT_EQ(miscTypes.getQName(), "abcd");
+  EXPECT_EQ(miscTypes.getIDREF(), "abcd");
+  EXPECT_EQ(miscTypes.getIDREFS()[0], "abcd");
+  EXPECT_EQ(miscTypes.getIDREFS()[1], "abcd");
+  EXPECT_EQ(miscTypes.getAnyType(), "abcd");
+
+  EXPECT_EQ(listPrimitiveTypes.getListInt()[0], -2147483648);
+  EXPECT_EQ(listPrimitiveTypes.getListInt()[1], 2147483647);
+  EXPECT_EQ(listPrimitiveTypes.getListShort()[0], -32768);
+  EXPECT_EQ(listPrimitiveTypes.getListShort()[1], 32767);
+  EXPECT_EQ((int)listPrimitiveTypes.getListByte()[0], -128);
+  EXPECT_EQ((int)listPrimitiveTypes.getListByte()[1], 127);
+  EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], 1234.56);
+  EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], 5678.12);
+  EXPECT_TRUE(listPrimitiveTypes.getListBoolean()[0]);
+  EXPECT_FALSE(listPrimitiveTypes.getListBoolean()[1]);
+
+  ofstream out("old_predefined_types.xml");
+  write(out, type);
+  Types type2 = *read("old_predefined_types.xml");
+
+  NumericTypes numericTypes2 = *type.getFirstNumericTypes();
+  ListPrimitiveTypes listPrimitiveTypes2 = *type.getFirstListPrimitiveTypes();
+
+  EXPECT_EQ(numericTypes.getDecimal(), numericTypes2.getDecimal());
+  EXPECT_EQ(numericTypes.getInteger(), numericTypes2.getInteger());
+  EXPECT_EQ(numericTypes.get_long(), numericTypes2.get_long());
+  EXPECT_EQ(numericTypes.get_int(), numericTypes2.get_int());
+  EXPECT_EQ(numericTypes.get_short(), numericTypes2.get_short());
+  EXPECT_EQ(numericTypes.getByte(), numericTypes2.getByte());
+  EXPECT_EQ(numericTypes.getNegativeInteger(), numericTypes2.getNegativeInteger());
+  EXPECT_EQ(numericTypes.getNonNegativeInteger(), numericTypes2.getNonNegativeInteger());
+  EXPECT_EQ(numericTypes.getPositiveInteger(), numericTypes2.getPositiveInteger());
+  EXPECT_EQ(numericTypes.getNonPositiveInteger(), numericTypes2.getNonPositiveInteger());
+  EXPECT_EQ(numericTypes.getUnsignedLong(), numericTypes2.getUnsignedLong());
+  EXPECT_EQ(numericTypes.getUnsignedInt(), numericTypes2.getUnsignedInt());
+  EXPECT_EQ(numericTypes.getUnsignedShort(), numericTypes2.getUnsignedShort());
+  EXPECT_EQ((numericTypes.getUnsignedByte()), numericTypes2.getUnsignedByte());
+
+  EXPECT_EQ(listPrimitiveTypes.getListInt()[0], listPrimitiveTypes2.getListInt()[0]);
+  EXPECT_EQ(listPrimitiveTypes.getListInt()[1], listPrimitiveTypes2.getListInt()[1]);
+  EXPECT_EQ(listPrimitiveTypes.getListShort()[0], listPrimitiveTypes2.getListShort()[0]);
+  EXPECT_EQ(listPrimitiveTypes.getListShort()[1], listPrimitiveTypes2.getListShort()[1]);
+  EXPECT_EQ(listPrimitiveTypes.getListByte()[0], listPrimitiveTypes2.getListByte()[0]);
+  EXPECT_EQ(listPrimitiveTypes.getListByte()[1], listPrimitiveTypes2.getListByte()[1]);
+  EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], listPrimitiveTypes2.getListDouble()[0]);
+  EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], listPrimitiveTypes2.getListDouble()[1]);
+  EXPECT_EQ(listPrimitiveTypes.getListBoolean()[0], listPrimitiveTypes2.getListBoolean()[0]);
+  EXPECT_EQ(listPrimitiveTypes.getListBoolean()[1], listPrimitiveTypes2.getListBoolean()[1]);
+}
+
+TEST_F(XmlTest, Nestedtype) {
+  using namespace nested::type;
+  Employee employee = *read(Resource("nested_type.xml").c_str());
+
+  Employee::Address address = *employee.getFirstAddress();
+  Employee::Address::Extra extra = *address.getFirstExtra();
+
+  EXPECT_EQ((int)employee.getId(), 1);
+  EXPECT_EQ(employee.getName(), "Peter");
+  EXPECT_EQ(address.getCountry(), "US");
+  EXPECT_EQ(address.getState(), "Mountain View");
+  EXPECT_EQ(address.getZip(), 3342);
+  EXPECT_EQ(extra.getLine1(), "Donga 303-111");
+  EXPECT_EQ(extra.getLine2(), "Good Street");
+
+  ofstream out("old_nested_type.xml");
+  write(out, employee);
+}
+
+TEST_F(XmlTest, Purchasesimple) {
+  using namespace purchase::simple;
+  PurchaseOrderType orderType = *read(Resource("purchase_simple.xml").c_str());
+
+  EXPECT_EQ(orderType.getOrderDate(), "1900-01-01");
+
+  EXPECT_EQ(orderType.getShipTo()[0].getName(), "name1");
+  EXPECT_EQ(orderType.getShipTo()[0].getStreet(), "street1");
+  EXPECT_EQ(orderType.getShipTo()[0].getCity(), "city1");
+  EXPECT_EQ(orderType.getShipTo()[0].getState(), "state1");
+  EXPECT_EQ(orderType.getShipTo()[0].getZip(), 1);
+  EXPECT_EQ(orderType.getShipTo()[0].getCountry(), "US");
+  EXPECT_EQ(orderType.getShipTo()[1].getName(), "name2");
+  EXPECT_EQ(orderType.getShipTo()[1].getStreet(), "street2");
+  EXPECT_EQ(orderType.getShipTo()[1].getCity(), "city2");
+  EXPECT_EQ(orderType.getShipTo()[1].getState(), "state2");
+  EXPECT_EQ(orderType.getShipTo()[1].getZip(), -7922816251426433759);
+  EXPECT_EQ(orderType.getShipTo()[1].getCountry(), "US");
+
+  EXPECT_EQ(orderType.getBillTo()[0].getName(), "billName");
+  EXPECT_EQ(orderType.getBillTo()[0].getStreet(), "billStreet");
+  EXPECT_EQ(orderType.getBillTo()[0].getCity(), "billCity");
+  EXPECT_EQ(orderType.getBillTo()[0].getState(), "billState");
+  EXPECT_EQ(orderType.getBillTo()[0].getZip(), 1);
+  EXPECT_EQ(orderType.getBillTo()[0].getCountry(), "US");
+
+  ofstream out("old_purchase_simple.xml");
+  write(out, orderType);
+
+  PurchaseOrderType orderType2 = *read("old_purchase_simple.xml");
+
+  EXPECT_EQ(orderType.getOrderDate(), orderType2.getOrderDate());
+
+  EXPECT_EQ(orderType.getShipTo()[0].getName(), orderType2.getShipTo()[0].getName());
+  EXPECT_EQ(orderType.getShipTo()[0].getStreet(), orderType2.getShipTo()[0].getStreet());
+  EXPECT_EQ(orderType.getShipTo()[0].getCity(), orderType2.getShipTo()[0].getCity());
+  EXPECT_EQ(orderType.getShipTo()[0].getState(), orderType2.getShipTo()[0].getState());
+  EXPECT_EQ(orderType.getShipTo()[0].getZip(), orderType2.getShipTo()[0].getZip());
+  EXPECT_EQ(orderType.getShipTo()[0].getCountry(), orderType2.getShipTo()[0].getCountry());
+  EXPECT_EQ(orderType.getShipTo()[1].getName(), orderType2.getShipTo()[1].getName());
+  EXPECT_EQ(orderType.getShipTo()[1].getStreet(), orderType2.getShipTo()[1].getStreet());
+  EXPECT_EQ(orderType.getShipTo()[1].getCity(), orderType2.getShipTo()[1].getCity());
+  EXPECT_EQ(orderType.getShipTo()[1].getState(), orderType2.getShipTo()[1].getState());
+  EXPECT_EQ(orderType.getShipTo()[1].getZip(), orderType2.getShipTo()[1].getZip());
+  EXPECT_EQ(orderType.getShipTo()[1].getCountry(), orderType2.getShipTo()[1].getCountry());
+
+  EXPECT_EQ(orderType.getBillTo()[0].getName(), orderType2.getBillTo()[0].getName());
+  EXPECT_EQ(orderType.getBillTo()[0].getStreet(), orderType2.getBillTo()[0].getStreet());
+  EXPECT_EQ(orderType.getBillTo()[0].getCity(), orderType2.getBillTo()[0].getCity());
+  EXPECT_EQ(orderType.getBillTo()[0].getState(), orderType2.getBillTo()[0].getState());
+  EXPECT_EQ(orderType.getBillTo()[0].getZip(), orderType2.getBillTo()[0].getZip());
+  EXPECT_EQ(orderType.getBillTo()[0].getCountry(), orderType2.getBillTo()[0].getCountry());
+}
+
+TEST_F(XmlTest, Reference) {
+  using namespace reference;
+  Class _class = *read(Resource("reference.xml").c_str());
+
+  EXPECT_EQ(_class.getStudent()[0], "Sam");
+  EXPECT_EQ(_class.getStudent()[1], "Paul");
+  EXPECT_EQ(_class.getStudent()[2], "Peter");
+
+  ofstream out("old_reference.xml");
+  write(out, _class);
+}
+
+TEST_F(XmlTest, Simplecomplexcontent) {
+  using namespace simple::complex::content;
+  Person person = *readPerson(Resource("simple_complex_content.xml").c_str());
+  USAddressP uSAddressP = *person.getFirstUSAddressP();
+  KRAddress kRAddress = *person.getFirstKRAddress();
+  SubAddress subAddress = *person.getFirstSubAddress();
+
+  EXPECT_EQ(person.getName(), "Petr");
+
+  EXPECT_EQ(uSAddressP.getName(), "404");
+  EXPECT_EQ(uSAddressP.getStreet(), "street fighter");
+  EXPECT_EQ(uSAddressP.getCity(), "New York");
+  EXPECT_EQ(uSAddressP.getState(), "Washington");
+  EXPECT_EQ(uSAddressP.getZipcode(), 323232318329852);
+
+  EXPECT_EQ(kRAddress.getName(), "Donga Studio");
+  EXPECT_EQ(kRAddress.getStreet(), "Nokdu Street");
+  EXPECT_EQ(kRAddress.getCity(), "Seoul");
+
+  EXPECT_EQ(subAddress.getChoice1_optional(), "Temp");
+
+  ofstream out("old_simple_complex_content.xml");
+  write(out, person);
+}
+
+TEST_F(XmlTest, Attrgroupsimple) {
+  using namespace attr::group::simple;
+  Student student = *read(Resource("attr_group_simple.xml").c_str());
+
+  EXPECT_EQ(student.getName(), "Jun");
+  EXPECT_EQ(student.getCity(), "Mountain View");
+  EXPECT_EQ(student.getState(), "CA");
+  EXPECT_EQ(student.getRoad(), "Street 101");
+  EXPECT_EQ(student.getList()[0], 1);
+  EXPECT_EQ(student.getList()[1], 2);
+  EXPECT_EQ(student.getList()[2], 3);
+
+  ofstream out("old_attr_group_simple.xml");
+  write(out, student);
+}
+
+TEST_F(XmlTest, Group) {
+  using namespace group;
+  Student student = *read(Resource("group.xml").c_str());
+
+  EXPECT_EQ(student.getCity(), "Mountain View");
+  EXPECT_EQ(student.getState(), "CA");
+  EXPECT_EQ(student.getRoad(), "Street 101");
+
+  ofstream out("old_group.xml");
+  write(out, student);
+}
diff --git a/tests/xmltest.h b/tests/xmltest.h
new file mode 100644
index 0000000..b645b98
--- /dev/null
+++ b/tests/xmltest.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+
+class XmlTest : public ::testing::Test {
+public:
+    std::string Resource(const std::string& filename) {
+      return ::android::base::GetExecutableDirectory() + "/resources/" + filename;
+    }
+};