From 20919f5c21d591d9bf4ec327b8a4c5edbbfaa884 Mon Sep 17 00:00:00 2001 From: Michael Ganss Date: Fri, 27 Jul 2018 13:40:22 +0200 Subject: [PATCH] Add tableau test Exclude IATA test (takes too long) Only test schema valid xml samples Better (still hacky) support for choices (fixes #76) Always use DateTime for xs:time --- XmlSampleGenerator/Generator.cs | 12 +- XmlSchemaClassGenerator.Console/Program.cs | 3 - XmlSchemaClassGenerator.Tests/Compiler.cs | 1 - .../XmlSchemaClassGenerator.Tests.csproj | 159 ++++ XmlSchemaClassGenerator.Tests/XmlTests.cs | 166 ++-- .../xsd/iata/aidm_commontypes.xsd | 8 +- .../xsd/ts-api/ts-api_2_8.xsd | 816 ++++++++++++++++++ XmlSchemaClassGenerator/CodeUtilities.cs | 14 +- XmlSchemaClassGenerator/Generator.cs | 6 - .../GeneratorConfiguration.cs | 5 - XmlSchemaClassGenerator/ModelBuilder.cs | 6 +- 11 files changed, 1072 insertions(+), 124 deletions(-) create mode 100644 XmlSchemaClassGenerator.Tests/xsd/ts-api/ts-api_2_8.xsd diff --git a/XmlSampleGenerator/Generator.cs b/XmlSampleGenerator/Generator.cs index 5d8c1028..dff86deb 100644 --- a/XmlSampleGenerator/Generator.cs +++ b/XmlSampleGenerator/Generator.cs @@ -297,8 +297,7 @@ public object GetEnumerationValue() { } public void ProcessLengthFacet(ref StringBuilder genString, int index) { int pLength = genString.Length; - int indexLen = index.ToString().Length; - int correctLen = length - indexLen; + int correctLen = length; if(pLength > correctLen) { genString.Remove(correctLen,pLength-correctLen); } @@ -324,8 +323,7 @@ public void ProcessMinLengthFacet(ref StringBuilder genString, int index) { public void ProcessMaxLengthFacet(ref StringBuilder genString, int index) { int pLength = genString.Length; - int indexLen = index.ToString().Length; - int correctLen = maxLength - indexLen; + int correctLen = maxLength; if(pLength > correctLen) { genString.Remove(correctLen,pLength-correctLen); } @@ -371,17 +369,17 @@ public override string GenerateValue() { } else { if(length != -1) { // The length facet is set - ProcessLengthFacet(ref genString, endValue); genString.Append(endValue); + ProcessLengthFacet(ref genString, endValue); } else { - if(minLength != -1) { + genString.Append(endValue); + if (minLength != -1) { ProcessMinLengthFacet(ref genString, endValue); } if(maxLength != -1) { ProcessMaxLengthFacet(ref genString, endValue); } - genString.Append(endValue); } } string result = genString.ToString(); diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index 18caaec4..8ef63a1e 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -36,7 +36,6 @@ static void Main(string[] args) var generateDebuggerStepThroughAttribute = true; var disableComments = false; var doNotUseUnderscoreInPrivateMemberNames = false; - var timeType = false; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -80,7 +79,6 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "dst|debuggerStepThrough", "generate DebuggerStepThroughAttribute (default is enabled)", v => generateDebuggerStepThroughAttribute = v != null }, { "dc|disableComments", "do not include comments from xsd", v => disableComments = v != null }, { "nu|noUnderscore", "do not generate underscore in private member name (default is false)", v => doNotUseUnderscoreInPrivateMemberNames = v != null }, - { "tt|timeAsDateTime", "map xs:time to DateTime instead of string", v => timeType = v != null }, }; var files = options.Parse(args); @@ -124,7 +122,6 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l TextValuePropertyName = textValuePropertyName, GenerateDebuggerStepThroughAttribute = generateDebuggerStepThroughAttribute, DisableComments = disableComments, - TimeDataType = timeType ? typeof(DateTime) : typeof(string) }; if (pclCompatible) diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index 2fae26dc..155e530e 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -78,7 +78,6 @@ public static Assembly GenerateFiles(string name, IEnumerable files, Gen EntityFramework = generatorPrototype.EntityFramework, GenerateInterfaces = generatorPrototype.GenerateInterfaces, MemberVisitor = generatorPrototype.MemberVisitor, - TimeDataType = generatorPrototype.TimeDataType }; gen.Generate(files); diff --git a/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj b/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj index 0c4ddb16..a5b5fd89 100644 --- a/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj +++ b/XmlSchemaClassGenerator.Tests/XmlSchemaClassGenerator.Tests.csproj @@ -172,6 +172,162 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Never + PreserveNewest @@ -265,6 +421,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 8aaba7ca..d3d0985a 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -33,7 +33,6 @@ private IEnumerable ConvertXml(string name, string xsd, Generator genera EntityFramework = generatorPrototype.EntityFramework, GenerateInterfaces = generatorPrototype.GenerateInterfaces, MemberVisitor = generatorPrototype.MemberVisitor, - TimeDataType = generatorPrototype.TimeDataType }; var set = new XmlSchemaSet(); @@ -57,17 +56,48 @@ private IEnumerable ConvertXml(string name, string xsd, Generator genera const string IS24ImmoTransferPattern = @"xsd\is24immotransfer\is24immotransfer.xsd"; const string WadlPattern = @"xsd\wadl\*.xsd"; const string ClientPattern = @"xsd\client\client.xsd"; - const string IataPattern = @"xsd\iata\????[^_][^_]?[^-]*.xsd"; + const string IataPattern = @"xsd\iata\*.xsd"; const string TimePattern = @"xsd\time\time.xsd"; + const string TableauPattern = @"xsd\ts-api\*.xsd"; + + // IATA test takes too long to perform every time + + //[Fact, TestPriority(1)] + //[UseCulture("en-US")] + //public void TestIata() + //{ + // Compiler.Generate("Iata", IataPattern, new Generator + // { + // EntityFramework = true, + // DataAnnotationMode = DataAnnotationMode.All, + // NamespaceProvider = new Dictionary { { new NamespaceKey(""), "XmlSchema" }, { new NamespaceKey("http://www.iata.org/IATA/EDIST/2017.2"), "Iata" } } + // .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "Iata" }.NamespaceProvider.GenerateNamespace), + // MemberVisitor = (member, model) => { }, + // GenerateInterfaces = true + // }); + // TestSamples("Iata", IataPattern); + //} [Fact, TestPriority(1)] [UseCulture("en-US")] - public void CanDeserializeSampleXml() + public void TestClient() { Compiler.Generate("Client", ClientPattern); TestSamples("Client", ClientPattern); + } + + [Fact, TestPriority(1)] + [UseCulture("en-US")] + public void TestIS24RestApi() + { Compiler.Generate("IS24RestApi", IS24Pattern); TestSamples("IS24RestApi", IS24Pattern); + } + + [Fact, TestPriority(1)] + [UseCulture("en-US")] + public void TestWadl() + { Compiler.Generate("Wadl", WadlPattern, new Generator { EntityFramework = true, @@ -76,18 +106,22 @@ public void CanDeserializeSampleXml() MemberVisitor = (member, model) => { } }); TestSamples("Wadl", WadlPattern); + } + + [Fact, TestPriority(1)] + [UseCulture("en-US")] + public void TestIS24ImmoTransfer() + { Compiler.Generate("IS24ImmoTransfer", IS24ImmoTransferPattern); TestSamples("IS24ImmoTransfer", IS24ImmoTransferPattern); - Compiler.Generate("Iata", IataPattern, new Generator - { - EntityFramework = true, - DataAnnotationMode = DataAnnotationMode.All, - NamespaceProvider = new Dictionary { { new NamespaceKey(""), "XmlSchema" }, { new NamespaceKey("http://www.iata.org/IATA/EDIST/2017.2"), "Iata" } } - .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "Wadl" }.NamespaceProvider.GenerateNamespace), - MemberVisitor = (member, model) => { }, - GenerateInterfaces = true - }); - TestSamples("Iata", IataPattern); + } + + [Fact, TestPriority(1)] + [UseCulture("en-US")] + public void TestTableau() + { + Compiler.Generate("Tableau", TableauPattern, new Generator()); + TestSamples("Tableau", TableauPattern); } private void TestSamples(string name, string pattern) @@ -115,7 +149,7 @@ private void DeserializeSampleXml(string pattern, Assembly assembly) set.Compile(); - foreach (var rootElement in set.GlobalElements.Values.Cast().Where(e => !e.IsAbstract)) + foreach (var rootElement in set.GlobalElements.Values.Cast().Where(e => !e.IsAbstract && !(e.ElementSchemaType is XmlSchemaSimpleType))) { var type = FindType(assembly, rootElement.QualifiedName); var serializer = new XmlSerializer(type); @@ -127,6 +161,27 @@ private void DeserializeSampleXml(string pattern, Assembly assembly) generator.WriteXml(xw); var xml = sb.ToString(); + // validate serialized xml + var settings = new XmlReaderSettings + { + ValidationType = ValidationType.Schema, + Schemas = set + }; + + var invalid = false; + + settings.ValidationEventHandler += (s, e) => + { + if (e.Severity == XmlSeverityType.Error) + invalid = true; + }; + + var reader = XmlReader.Create(new StringReader(xml), settings); + while (reader.Read()) ; + + // generated xml is not schema valid -> skip + if (invalid) continue; + File.WriteAllText("xml.xml", xml); // deserialize from sample @@ -138,23 +193,12 @@ private void DeserializeSampleXml(string pattern, Assembly assembly) File.WriteAllText("xml2.xml", xml2); - // validate serialized xml - XmlReaderSettings settings = new XmlReaderSettings - { - ValidationType = ValidationType.Schema, - Schemas = set - }; - settings.ValidationEventHandler += (s, e) => { - // generator doesn't generate valid values where pattern restrictions exist, e.g. email - if (!e.Message.Contains("The Pattern constraint failed")) - { - Assert.True(false, e.Message); - } + throw e.Exception; }; - XmlReader reader = XmlReader.Create(new StringReader(xml2), settings); + reader = XmlReader.Create(new StringReader(xml2), settings); while (reader.Read()) ; // deserialize again @@ -278,67 +322,19 @@ string ReadXml(string name) return xml; } - /// - /// When the TimeDataType is set to use the DateTime, creating a serialiser against types - /// that use xsd:time should no longer throw exceptions. - /// [Fact] - public void CreateDeserialiser_NoException_WhereTimeXsdPresent_AndTimeDataTypeSet() + public void DontGenerateElementForEmptyCollectionInChoice() { - Compiler.Generate("Time1", TimePattern, new Generator - { - EntityFramework = true, - DataAnnotationMode = DataAnnotationMode.All, - NamespaceProvider = new Dictionary - { - {new NamespaceKey("http://hic.gov.au/hiconline/medicare/version-4"), "hiconline"} - } - .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "time" }.NamespaceProvider - .GenerateNamespace), - MemberVisitor = (member, model) => { }, - GenerateInterfaces = true, - TimeDataType = typeof(DateTime) - }); - - var assembly = Compiler.GetAssembly("Time1"); + var assembly = Compiler.Generate("Tableau", TableauPattern, new Generator()); Assert.NotNull(assembly); - - var type = assembly.GetType("hiconline.Service"); - Assert.NotNull(type); - - var serializer = new XmlSerializer(type); // exception not thrown - Assert.NotNull(serializer); - } - - /// - /// Test to ensure existing behaviour not changed. - /// - [Fact] - public void CreateDeserialiser_ThrowsException_WhereTimeXsdPresent_AndTimeDataTypeNotSet() - { - Compiler.Generate("Time2", TimePattern, new Generator - { - EntityFramework = true, - DataAnnotationMode = DataAnnotationMode.All, - NamespaceProvider = new Dictionary - { - {new NamespaceKey("http://hic.gov.au/hiconline/medicare/version-4"), "hiconline"} - } - .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "time" }.NamespaceProvider - .GenerateNamespace), - MemberVisitor = (member, model) => { }, - GenerateInterfaces = true - }); - - var assembly = Compiler.GetAssembly("Time2"); - Assert.NotNull(assembly); - - var type = assembly.GetType("hiconline.Service"); - Assert.NotNull(type); - - var ex = Assert.Throws(() => new XmlSerializer(type)); - Assert.NotNull(ex); - Assert.Equal("There was an error reflecting type 'hiconline.Service'.", ex.Message); + var requestType = assembly.GetType("Api.TsRequest"); + Assert.NotNull(requestType); + var r = Activator.CreateInstance(requestType); + var s = new XmlSerializer(requestType); + var sw = new StringWriter(); + s.Serialize(sw, r); + var xml = sw.ToString(); + Assert.DoesNotContain("tags", xml, StringComparison.OrdinalIgnoreCase); } [Fact] diff --git a/XmlSchemaClassGenerator.Tests/xsd/iata/aidm_commontypes.xsd b/XmlSchemaClassGenerator.Tests/xsd/iata/aidm_commontypes.xsd index 8ed1f274..6a2094f5 100644 --- a/XmlSchemaClassGenerator.Tests/xsd/iata/aidm_commontypes.xsd +++ b/XmlSchemaClassGenerator.Tests/xsd/iata/aidm_commontypes.xsd @@ -108,7 +108,7 @@ Example: http://www.oneworld.com/home - + The presence of the empty ContactNotProvided element indicates that the passenger refused to provide contact information. @@ -238,7 +238,7 @@ In the absence of a formal identity document, a driver's license may be accepted - The type of passenger document. + The type of passenger document. Examples: PT (Passport) @@ -619,7 +619,7 @@ This is the type of FOID as defined in AIRIMP (FF Number, Credit Card Number, et - Used to differentiate multiple Phone numbers of one contact. + Used to differentiate multiple Phone numbers of one contact. Examples: Work, Home, Mobile @@ -636,7 +636,7 @@ Examples: Work, Home, Mobile Phone number text. -Eg: +1 999-999-9999 ext 1234, +Eg: +1 999-999-9999 ext 1234, 617-9976 Note: This may be a simple, un-structured phone number, such as +01 999-999-9999 ext 1234 or combined with the additional attributes to create a structured phone number. diff --git a/XmlSchemaClassGenerator.Tests/xsd/ts-api/ts-api_2_8.xsd b/XmlSchemaClassGenerator.Tests/xsd/ts-api/ts-api_2_8.xsd new file mode 100644 index 00000000..d07e7b6b --- /dev/null +++ b/XmlSchemaClassGenerator.Tests/xsd/ts-api/ts-api_2_8.xsd @@ -0,0 +1,816 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Not a real value. Used to specify 'no limit' when site is created or updated. Never returned from server in response. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XmlSchemaClassGenerator/CodeUtilities.cs b/XmlSchemaClassGenerator/CodeUtilities.cs index b50a559f..6e0237b8 100644 --- a/XmlSchemaClassGenerator/CodeUtilities.cs +++ b/XmlSchemaClassGenerator/CodeUtilities.cs @@ -95,16 +95,10 @@ private static Type GetEffectiveType(XmlTypeCode typeCode, XmlSchemaDatatypeVari result = variety == XmlSchemaDatatypeVariety.List ? typeof(string[]) : typeof(string); break; case XmlTypeCode.Time: - if (configuration.TimeDataType == null || configuration.TimeDataType == typeof(string)) - { - // default to string - result = typeof(string); - } - else - { - // otherwise, use the specified type - result = configuration.TimeDataType; - } + result = typeof(DateTime); + break; + case XmlTypeCode.Idref: + result = typeof(string); break; case XmlTypeCode.Integer: case XmlTypeCode.NegativeInteger: diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 2746b5d8..9da84e2a 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -187,12 +187,6 @@ public bool DoNotUseUnderscoreInPrivateMemberNames set { _configuration.DoNotUseUnderscoreInPrivateMemberNames = value; } } - public Type TimeDataType - { - get { return _configuration.TimeDataType; } - set { _configuration.TimeDataType = value; } - } - public void Generate(IEnumerable files) { var set = new XmlSchemaSet(); diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index 30b2cbbb..fb857f62 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -167,10 +167,5 @@ public void WriteLog(string message) public bool DisableComments { get; set; } public bool DoNotUseUnderscoreInPrivateMemberNames { get; set; } - - /// - /// Default data type for time fields. Defaults to string if not set. - /// - public Type TimeDataType { get; set; } } } diff --git a/XmlSchemaClassGenerator/ModelBuilder.cs b/XmlSchemaClassGenerator/ModelBuilder.cs index 082cec82..fab0f1ed 100644 --- a/XmlSchemaClassGenerator/ModelBuilder.cs +++ b/XmlSchemaClassGenerator/ModelBuilder.cs @@ -519,9 +519,9 @@ private IEnumerable CreatePropertiesForElements(Uri source, TypeM Name = propertyName, Type = CreateTypeModel(source, element.ElementSchemaType, elementQualifiedName), IsNillable = element.IsNillable, - IsNullable = item.MinOccurs < 1.0m, + IsNullable = item.MinOccurs < 1.0m || (particle is XmlSchemaChoice), IsCollection = item.MaxOccurs > 1.0m || particle.MaxOccurs > 1.0m, // http://msdn.microsoft.com/en-us/library/vstudio/d3hx2s7e(v=vs.100).aspx - DefaultValue = element.DefaultValue ?? (item.MinOccurs >= 1.0m ? element.FixedValue : null), + DefaultValue = element.DefaultValue ?? ((item.MinOccurs >= 1.0m && !(particle is XmlSchemaChoice)) ? element.FixedValue : null), Form = element.Form == XmlSchemaForm.None ? element.GetSchema().ElementFormDefault : element.Form, XmlNamespace = element.QualifiedName.Namespace != "" && element.QualifiedName.Namespace != typeModel.XmlSchemaName.Namespace ? element.QualifiedName.Namespace : null, }; @@ -535,7 +535,7 @@ private IEnumerable CreatePropertiesForElements(Uri source, TypeM OwningType = typeModel, Name = "Any", Type = new SimpleModel(_configuration) { ValueType = (_configuration.UseXElementForAny ? typeof(XElement) : typeof(XmlElement)), UseDataTypeAttribute = false }, - IsNullable = item.MinOccurs < 1.0m, + IsNullable = item.MinOccurs < 1.0m || (particle is XmlSchemaChoice), IsCollection = item.MaxOccurs > 1.0m || particle.MaxOccurs > 1.0m, // http://msdn.microsoft.com/en-us/library/vstudio/d3hx2s7e(v=vs.100).aspx IsAny = true, };