public Member(Env env, Composite parent, string name, Type type) { // In this function, we must fully define what type we are (important in the case of Dec or containers) // and also set our default value (if relevant.) this.parent = parent; this.name = name; this.type = type; if (type == Type.Composite) { if (parent.type == Composite.Type.Struct) { // We only want to include structs that happen after us in the type list var structs = env.types.SkipWhile(etype => etype != parent).Skip(1).Where(etype => etype.type == Composite.Type.Struct); var classes = env.types.Where(etype => etype.type == Composite.Type.Class); compositeChild = structs.Concat(classes).RandomElement(); } else { compositeChild = env.types.Where(etype => etype.type != Composite.Type.Dec).RandomElement(); } if (parent.type == Composite.Type.Struct) { initialized = null; // won't be used anywhere anyway, just fall back on defaults } else { initialized = new ValueComposite(env, compositeChild); } } else if (type == Type.Dec) { compositeChild = env.types.Where(inst => inst.type == Composite.Type.Dec).RandomElement(); initialized = new ValueSimple("null", ""); } else if (type == Type.ContainerList) { containerValue = new Member(env, parent, null, MemberTypeDistribution.Distribution.Choose()); initialized = new ValueSimple("null", ""); } else if (type == Type.ContainerDictionary) { containerKey = new Member(env, parent, null, MemberTypeDistribution.DictKeyDistribution.Choose()); containerValue = new Member(env, parent, null, MemberTypeDistribution.Distribution.Choose()); initialized = new ValueSimple("null", ""); } else if (parent.type == Composite.Type.Struct) { // structs always init to basic types if (type == Type.String || type == Type.Composite && this.compositeChild.type != Composite.Type.Struct) { initialized = new ValueSimple("null"); } else if (type == Type.Bool) { initialized = new ValueSimple("false"); } else if (type != Type.Composite) { initialized = new ValueSimple("0"); } // otherwise it's a struct composite and we don't really have anything sensible to compare it to } else { initialized = GenerateValue(env); } }
private static void Main() { Init(); var env = new Env(); // Generate initial composites for (int i = 0; i < 100; ++i) { var c = new Composite(); c.name = Rand.NextString(); c.type = CompositeTypeDistribution.Distribution.Choose(); if (c.type == Composite.Type.Dec) { c.name += "Dec"; } env.types.Add(c); } // Generate parameters foreach (var c in env.types) { int parameterCount = Rand.WeightedDistribution(); for (int i = 0; i < parameterCount; ++i) { c.members.Add(new Member(env, c, Rand.NextString(), MemberTypeDistribution.Distribution.Choose())); } } // Generate instances foreach (var c in env.types) { if (c.type != Composite.Type.Dec) { continue; } int creations = Rand.WeightedDistribution(); for (int i = 0; i < creations; ++i) { env.instances.Add(new Instance(env, c)); } } string GenerateTestHarness(string testData) { string testHarness = File.ReadAllText("data/TestHarness.cs.template"); var csComposites = new StringBuilder(); foreach (var c in env.types) { csComposites.Append(Util.Indent(c.WriteCsharpDefinition(), 2)); } var types = string.Join(", ", env.types.Select(c => $"typeof({c.name})")); var filename = "data/Fuzzgen.FuzzgenTest.xml"; return(testHarness .Replace("<<COMPOSITES>>", csComposites.ToString()) .Replace("<<TYPES>>", types) .Replace("<<FILENAME>>", $"\"{filename}\"") .Replace("<<TESTS>>", testData)); } string testCode = GenerateTestHarness(""); string xmlCode; // Output xml { var sb = new StringBuilder(); sb.AppendLine("<Decs>"); foreach (var i in env.instances) { sb.AppendLine(Util.Indent(i.WriteXmlDec())); } sb.AppendLine("</Decs>"); xmlCode = sb.ToString(); } // This is a bit janky; we want to use Dec features when doing generation, but now we need to blow it away to generate the .cs code // So I guess maybe it would be nice to have non-global state right now :V Dec.Database.Clear(); var bootstrapAssembly = DecUtilLib.Compilation.Compile(testCode, new System.Reflection.Assembly[] { }); bootstrapAssembly.GetType("DecTest.Harness").GetMethod("Setup").Invoke(null, null); var parser = new Dec.Parser(); parser.AddString(xmlCode); parser.Finish(); var composer = new Dec.Composer(); var tests = composer.ComposeValidation(); string finalCode = GenerateTestHarness(tests); string path = $"../../test/data/golden/parser/{System.DateTimeOffset.Now:yyyyMMddhhmmss}"; System.IO.Directory.CreateDirectory(path); DecUtilLib.Compress.WriteToFile(System.IO.Path.Combine(path, "Harness.cs"), finalCode); DecUtilLib.Compress.WriteToFile(System.IO.Path.Combine(path, "data.xml"), xmlCode); }