public void demoDefaultingForUserguide()
        {
            // create the test data
            ManyDefaultsTestData md = new ManyDefaultsTestData();

            // create an aliaser to create identifiers for types
            // must emit valid js property name distinct for each class
            // typically a number is used to reduce size
            TypeAliaser aliaser = TypeAliaserUtils.createNumericTypeNameAliaser();

            //focus on serializing fields
            NodeExpander nodeExpander = new FieldReflectionNodeExpander();
            // find the defaults - this is a one off
            // only necessary once per schemachange
            DefaultFinder df = new DefaultFinder();
            // this method just searches through the type structure
            LeafDefaultSet lds = df.getDefaultsForAllLinkedObjects(md, nodeExpander);
            // create a dictionary of default values - this is a one off per schemachange
            Dictionary <string, Defaults4Class> defaultValues = lds.getAlias2Defaults(aliaser);

            Object2Json o2J = new Object2Json();

            o2J.TypeAliaser  = aliaser;
            o2J.NodeExpander = nodeExpander;
            // make the format prettier
            o2J.IndentSize = 2;
            // create javascript representing the dictionary of defaults
            String defaultValuesJson = o2J.toJson(defaultValues);

            System.Console.WriteLine("defaultValuesJson=" + defaultValuesJson);

            // serialise without defaults
            o2J.OmitDefaultLeafValuesInJs = true;
            o2J.LeafDefaultSet            = lds;
            o2J.OmitMarkAsArrayFunction   = false;
            String withoutDefaultsLeafValuesJS = o2J.toJson(md);

            System.Console.WriteLine("withoutDefaultsLeafValuesJS=" + withoutDefaultsLeafValuesJS);

            // serialise with defaults
            o2J.OmitDefaultLeafValuesInJs = false;
            o2J.LeafDefaultSet            = lds;
            o2J.TypeAliaser = aliaser;
            String withDefaultLeafValuesJS = o2J.toJson(md);

            System.Console.WriteLine("withDefaultLeafValuesJS=" + withDefaultLeafValuesJS);

            JSExcuteUtil.JsonValueSet valueSet = new JSExcuteUtil.JsonValueSet();
            valueSet.json    = o2J.LeafDefaultResolverFunctionName + "(" + withoutDefaultsLeafValuesJS + ")";
            valueSet.varname = "defaulted";
            valueSet.extraFunctions.Add(o2J.getLeafDefaultResolverJS(aliaser));
            valueSet.extraFunctions.Add(o2J.getMarkAsArrayJSFunction());
            valueSet.significance = "serialised without default values and restore with standard restore js function";
            valueSet.expressions2ExpectedValue["stringValuesArr[1].str2"] = md.stringValuesArr[1].str2;
            valueSet.expressions2ExpectedValue["stringValuesArr[2].aReallyReallyReallyLongName"] = md.stringValuesArr[2].aReallyReallyReallyLongName;
            Dictionary <string, object> values = util.extractValuesFromJson(valueSet, GetType().Name + "." + "demoDefaultingForUserguide");
        }
        public void demoDefaultingForUserguide()
        {
            // create the test data
            ManyDefaultsTestData md = new ManyDefaultsTestData();

            // create an aliaser to create identifiers for types
            // must emit valid js property name distinct for each class
            // typically a number is used to reduce size
            TypeAliaser aliaser = TypeAliaserUtils.createNumericTypeNameAliaser();

            //focus on serializing fields
            NodeExpander nodeExpander = new FieldReflectionNodeExpander();
            // find the defaults - this is a one off
            // only necessary once per schemachange
            DefaultFinder df = new DefaultFinder();
            // this method just searches through the type structure
            LeafDefaultSet lds = df.getDefaultsForAllLinkedObjects(md, nodeExpander);
            // create a dictionary of default values - this is a one off per schemachange
            Dictionary<string, Defaults4Class> defaultValues = lds.getAlias2Defaults(aliaser);

            Object2Json o2J = new Object2Json();
            o2J.TypeAliaser = aliaser;
            o2J.NodeExpander = nodeExpander;
            // make the format prettier
            o2J.IndentSize = 2;
            // create javascript representing the dictionary of defaults
            String defaultValuesJson = o2J.toJson(defaultValues);
            System.Console.WriteLine("defaultValuesJson=" + defaultValuesJson);

            // serialise without defaults
            o2J.OmitDefaultLeafValuesInJs = true;
            o2J.LeafDefaultSet = lds;
            o2J.OmitMarkAsArrayFunction = false;
            String withoutDefaultsLeafValuesJS = o2J.toJson(md);
            System.Console.WriteLine("withoutDefaultsLeafValuesJS=" + withoutDefaultsLeafValuesJS);

            // serialise with defaults
            o2J.OmitDefaultLeafValuesInJs = false;
            o2J.LeafDefaultSet = lds;
            o2J.TypeAliaser = aliaser;
            String withDefaultLeafValuesJS = o2J.toJson(md);

            System.Console.WriteLine("withDefaultLeafValuesJS=" + withDefaultLeafValuesJS);

            JSExcuteUtil.JsonValueSet valueSet = new JSExcuteUtil.JsonValueSet();
            valueSet.json = o2J.LeafDefaultResolverFunctionName + "(" + withoutDefaultsLeafValuesJS + ")";
            valueSet.varname = "defaulted";
            valueSet.extraFunctions.Add(o2J.getLeafDefaultResolverJS(aliaser));
            valueSet.extraFunctions.Add(o2J.getMarkAsArrayJSFunction());
            valueSet.significance = "serialised without default values and restore with standard restore js function";
            valueSet.expressions2ExpectedValue["stringValuesArr[1].str2"] = md.stringValuesArr[1].str2;
            valueSet.expressions2ExpectedValue["stringValuesArr[2].aReallyReallyReallyLongName"] = md.stringValuesArr[2].aReallyReallyReallyLongName;
            Dictionary<string, object> values = util.extractValuesFromJson(valueSet, GetType().Name + "." + "demoDefaultingForUserguide");
        }
        public void testDefaultingWritingDefaultsBit()
        {
            //todo autoreject invalid js aliases e.g. numberot dot contained
            Object2Json          o2j     = new Object2Json();
            DefaultFinder        df      = new DefaultFinder();
            ManyDefaultsTestData md      = new ManyDefaultsTestData();
            TypeAliaser          aliaser = delegate(Type type)
            {
                return(type.FullName.Replace('.', '_').Replace('+', '_'));
            };
            // need to pass in class name aliasing scheme
            // this will fail if aliases are not valid js propert names
            Dictionary <string, Defaults4Class> defaultsJS;

            String[]       expressions;
            object[]       expectedValues;
            NodeExpander   nodeExpander = new FieldReflectionNodeExpander();
            LeafDefaultSet lds          = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());

            defaultsJS  = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue" + ".i1",
                                         aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue" + ".str3" };
            expectedValues = new object[] { md.i1, md.stringValues.str3 };
            //check that the defaults serialise OK first
            Object2Json o2J = new Object2Json();

            o2J.NodeExpander = nodeExpander;
            o2J.IndentSize   = 2;
            String json = o2J.toJson(defaultsJS);

            validateJSON(json, expressions, expectedValues, "testDefaultingWritingDefaultsBit.simplealias", "using a verbose class aliaser");
            // try a numeric aliaser
            aliaser     = TypeAliaserUtils.createNumericTypeNameAliaser();
            lds         = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());
            defaultsJS  = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue" + ".i1",
                                         aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue" + ".str3" };
            o2J.IndentSize = 2;
            json           = o2J.toJson(defaultsJS);
            validateJSON(json, expressions, expectedValues, "testDefaultingWritingDefaultsBit.numericliaser", "using a compact numeric aliaser");
        }
        public static Object2Json DefaultObject2Json(Object testData)
        {
            Object2Json Object2Json;

            // Code that runs on application startup
            // create global serialiser here
            Object2Json = new Object2Json();
            Object2Json.UseReferences = true;
            Object2Json.NodeExpander  = new FieldReflectionNodeExpander();

            // add in defaults
            Object2Json.LeafDefaultSet = new LeafDefaultSet();
            Object2Json.TypeAliaser    = TypeAliaserUtils.createNumericTypeNameAliaser();

            DefaultFinder df = new DefaultFinder();
            //TypeAliaserUtils
            LeafDefaultSet lds = df.getDefaultsForAllLinkedObjects(testData, Object2Json.NodeExpander);

            Object2Json.LeafDefaultSet.Add(lds);
            return(Object2Json);
        }
        public void testDefaulting()
        {
            //todo autoreject invalid js aliases e.g. numberot dot contained
            //Object2Json o2j = new Object2Json();
            DefaultFinder        df      = new DefaultFinder();
            ManyDefaultsTestData md      = new ManyDefaultsTestData();
            TypeAliaser          aliaser = delegate(Type type)
            {
                return(type.FullName.Replace('.', '_').Replace('+', '_'));
            };
            // need to pass in class name aliasing scheme
            // this will fail if aliases are not valid js propert names
            Dictionary <string, Defaults4Class> defaultsJS;

            String[]       expressions;
            object[]       expectedValues;
            NodeExpander   nodeExpander = new FieldReflectionNodeExpander();
            LeafDefaultSet lds          = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());

            defaultsJS  = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue" + ".i1",
                                         aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue" + ".str3" };
            expectedValues = new object[] { md.i1, md.stringValues.str3 };
            //check that the defaults serialise OK first
            Object2Json o2J = new Object2Json();

            // should test with this as false
            o2J.UseReferences = true;
            o2J.NodeExpander  = nodeExpander;
            o2J.IndentSize    = 2;
            String json = o2J.toJson(defaultsJS);

            validateJSON(json, expressions, expectedValues, "testDefaulting.defaultMap", " check access to serialised defaults, class names are aliased replacing '.' with '_'");
            aliaser     = TypeAliaserUtils.createNumericTypeNameAliaser();
            lds         = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());
            defaultsJS  = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue" + ".i1",
                                         aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue" + ".str3" };
            o2J.IndentSize = 2;
            json           = o2J.toJson(defaultsJS);
            validateJSON(json, expressions, expectedValues, "testDefaulting", "check access to serialised defaults, classnames are aliases with numbers");

            // serialise with defaults
            o2J.OmitDefaultLeafValuesInJs = false;
            String withDefaultLeafValuesJS = o2J.toJson(md);

            // serialise without defaults
            o2J.OmitDefaultLeafValuesInJs = true;
            o2J.LeafDefaultSet            = lds;
            o2J.OmitMarkAsArrayFunction   = false;
            o2J.TypeAliaser = aliaser;
            String withoutDefaultsLeafValuesJS  = o2J.toJson(md);
            float  minimumDefaultingCompression = 2.0F;
            // check sizes is much smaller with defaults
            int maximumCompressedLength = (int)(((float)withDefaultLeafValuesJS.Length) / minimumDefaultingCompression);

            object [] vals = { withDefaultLeafValuesJS.Length };
            Assert.IsTrue(withoutDefaultsLeafValuesJS.Length < maximumCompressedLength, "without default compression length=" + withDefaultLeafValuesJS.Length +
                          " without default leaf values length=" + withoutDefaultsLeafValuesJS.Length + " but expected less than " + maximumCompressedLength + " (compression better than " + minimumDefaultingCompression + ")");
            // check defaulted values are undefined if undefault is not called
            expressions                 = new string[] { "i2", "stringValues.str3", "stringValues.str2", "stringValues.str1", "i1", "i4", "stringValuesArr[0].str1" };
            expectedValues              = new object[expressions.Length]; // assume initialised to null !!
            md.i2                       = 6789;
            expectedValues[0]           = md.i2;
            withoutDefaultsLeafValuesJS = o2J.toJson(md);
            string[] extraFunctions = { o2J.getAttachId2ArrayJSFunction() };
            validateJSON(withoutDefaultsLeafValuesJS, extraFunctions, expressions, expectedValues, "testDefaulting.unrestoredvalues", "serialise ommitting defaults and in js test do not restore defaults");

            expectedValues = new object[] { md.i2, md.stringValues.str3, md.stringValues.str2, md.stringValues.str1, md.i1, md.i4, md.stringValuesArr[0].str1 };
            //Object value;
            JSExcuteUtil.JsonValueSet valueSet = new JSExcuteUtil.JsonValueSet();
            valueSet.json    = o2J.LeafDefaultResolverFunctionName + "(" + withoutDefaultsLeafValuesJS + ")";
            valueSet.varname = "defaulted";
            for (int done = 0; done < expressions.Length; done++)
            {
                valueSet.expressions2ExpectedValue[expressions[done]] = expectedValues[done];
            }
            valueSet.extraFunctions.Add(o2J.getLeafDefaultResolverJS(aliaser));
            valueSet.extraFunctions.Add(o2J.getMarkAsArrayJSFunction());
            valueSet.extraFunctions.Add(o2J.getAttachId2ArrayJSFunction());
            valueSet.significance = "serialised without default values and restore with standard restore js function";
            Dictionary <string, object> values = util.extractValuesFromJson(valueSet, GetType().Name + "." + "testDefaulting.resolveLeaves");

            for (int done = 0; done < expressions.Length; done++)
            {
                string expression    = expressions[done];
                object expectedValue = expectedValues[done];
                object actualValue   = valueSet.expressions2ExpectedValue[expression] = values[expression];
                //"expression=" + expression + " with reference json= " + withoutDefaultsLeafValuesJS
                Assert.AreEqual(expectedValue, actualValue, "valueSet==" + valueSet.ToString());
            }
        }
 public void testDefaultingWritingDefaultsBit()
 {
     //todo autoreject invalid js aliases e.g. numberot dot contained
     Object2Json o2j = new Object2Json();
     DefaultFinder df = new DefaultFinder();
     ManyDefaultsTestData md = new ManyDefaultsTestData();
     TypeAliaser aliaser = delegate(Type type)
     {
         return type.FullName.Replace('.', '_').Replace('+', '_');
     };
     // need to pass in class name aliasing scheme
     // this will fail if aliases are not valid js propert names
     Dictionary<string, Defaults4Class> defaultsJS;
     String[] expressions;
     object[] expectedValues;
     NodeExpander nodeExpander = new FieldReflectionNodeExpander();
     LeafDefaultSet lds = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());
     defaultsJS = lds.getAlias2Defaults(aliaser);
     expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue"  +".i1",
                              aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue"  + ".str3"};
     expectedValues= new object[] { md.i1, md.stringValues.str3 };
     //check that the defaults serialise OK first
     Object2Json o2J = new Object2Json();
     o2J.NodeExpander = nodeExpander;
     o2J.IndentSize = 2;
     String json = o2J.toJson(defaultsJS);
     validateJSON(json, expressions, expectedValues, "testDefaultingWritingDefaultsBit.simplealias","using a verbose class aliaser");
     // try a numeric aliaser
     aliaser =  TypeAliaserUtils.createNumericTypeNameAliaser();
     lds = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());
     defaultsJS = lds.getAlias2Defaults(aliaser);
     expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue"  +".i1",
                              aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue"  + ".str3"};
     o2J.IndentSize = 2;
     json = o2J.toJson(defaultsJS);
     validateJSON(json, expressions, expectedValues, "testDefaultingWritingDefaultsBit.numericliaser", "using a compact numeric aliaser");
 }
        public void testDefaulting()
        {
            //todo autoreject invalid js aliases e.g. numberot dot contained
            //Object2Json o2j = new Object2Json();
            DefaultFinder df = new DefaultFinder();
            ManyDefaultsTestData md = new ManyDefaultsTestData();
            TypeAliaser aliaser = delegate(Type type)
            {
                return type.FullName.Replace('.', '_').Replace('+', '_');
            };
            // need to pass in class name aliasing scheme
            // this will fail if aliases are not valid js propert names
            Dictionary<string, Defaults4Class> defaultsJS;
            String[] expressions;
            object[] expectedValues;
            NodeExpander nodeExpander = new FieldReflectionNodeExpander();
            LeafDefaultSet lds = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander());
            defaultsJS = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue"  +".i1",
                                     aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue"  + ".str3"};
            expectedValues = new object[] { md.i1, md.stringValues.str3 };
            //check that the defaults serialise OK first
            Object2Json o2J = new Object2Json();
            // should test with this as false
            o2J.UseReferences = true;
            o2J.NodeExpander = nodeExpander;
            o2J.IndentSize = 2;
            String json = o2J.toJson(defaultsJS);
            validateJSON(json, expressions, expectedValues, "testDefaulting.defaultMap",  " check access to serialised defaults, class names are aliased replacing '.' with '_'");
            aliaser = TypeAliaserUtils.createNumericTypeNameAliaser();
            lds = df.getDefaultsForAllLinkedObjects(md, new FieldReflectionNodeExpander() );
            defaultsJS = lds.getAlias2Defaults(aliaser);
            expressions = new string[] { aliaser(md.GetType()) + ".propertyName2DefaultValue"  +".i1",
                                     aliaser(typeof(ManyDefaultsTestData.StringValues)) + ".propertyName2DefaultValue"  + ".str3"};
            o2J.IndentSize = 2;
            json = o2J.toJson(defaultsJS);
            validateJSON(json, expressions, expectedValues, "testDefaulting", "check access to serialised defaults, classnames are aliases with numbers");

            // serialise with defaults
            o2J.OmitDefaultLeafValuesInJs = false;
            String withDefaultLeafValuesJS = o2J.toJson(md);
            // serialise without defaults
            o2J.OmitDefaultLeafValuesInJs = true;
            o2J.LeafDefaultSet = lds;
            o2J.OmitMarkAsArrayFunction = false;
            o2J.TypeAliaser = aliaser;
            String withoutDefaultsLeafValuesJS = o2J.toJson(md);
            float minimumDefaultingCompression = 2.0F;
            // check sizes is much smaller with defaults
            int maximumCompressedLength= (int) (((float) withDefaultLeafValuesJS.Length) / minimumDefaultingCompression   );
            object []vals = {withDefaultLeafValuesJS.Length};
            Assert.IsTrue(withoutDefaultsLeafValuesJS.Length < maximumCompressedLength, "without default compression length=" + withDefaultLeafValuesJS.Length +
                  " without default leaf values length=" + withoutDefaultsLeafValuesJS.Length + " but expected less than " + maximumCompressedLength + " (compression better than " +minimumDefaultingCompression +")");
            // check defaulted values are undefined if undefault is not called
            expressions = new string[] { "i2", "stringValues.str3", "stringValues.str2", "stringValues.str1", "i1", "i4", "stringValuesArr[0].str1" };
            expectedValues = new object[expressions.Length]; // assume initialised to null !!
            md.i2 = 6789;
            expectedValues[0] = md.i2;
            withoutDefaultsLeafValuesJS = o2J.toJson(md);
            string[] extraFunctions = { o2J.getAttachId2ArrayJSFunction() };
            validateJSON(withoutDefaultsLeafValuesJS, extraFunctions, expressions, expectedValues, "testDefaulting.unrestoredvalues", "serialise ommitting defaults and in js test do not restore defaults");

             expectedValues = new object[] {md.i2, md.stringValues.str3, md.stringValues.str2, md.stringValues.str1, md.i1, md.i4, md.stringValuesArr[0].str1 };
             //Object value;
             JSExcuteUtil.JsonValueSet valueSet = new JSExcuteUtil.JsonValueSet();
             valueSet.json = o2J.LeafDefaultResolverFunctionName + "(" + withoutDefaultsLeafValuesJS + ")";
             valueSet.varname = "defaulted";
             for (int done = 0; done < expressions.Length; done++)
             {
                 valueSet.expressions2ExpectedValue[expressions[done]] = expectedValues[done];
             }
            valueSet.extraFunctions.Add(o2J.getLeafDefaultResolverJS(aliaser));
            valueSet.extraFunctions.Add(o2J.getMarkAsArrayJSFunction());
            valueSet.extraFunctions.Add(o2J.getAttachId2ArrayJSFunction());
            valueSet.significance = "serialised without default values and restore with standard restore js function";
             Dictionary<string, object> values = util.extractValuesFromJson(valueSet, GetType().Name + "." + "testDefaulting.resolveLeaves");

             for (int done = 0; done < expressions.Length; done++)
             {
                 string expression = expressions[done];
                 object expectedValue = expectedValues[done];
                 object actualValue = valueSet.expressions2ExpectedValue[expression] = values[expression];
                 //"expression=" + expression + " with reference json= " + withoutDefaultsLeafValuesJS
                 Assert.AreEqual(expectedValue, actualValue, "valueSet==" + valueSet.ToString());
             }
        }