diff --git a/ALObjectParser.Console/Program.cs b/ALObjectParser.Console/Program.cs index 8fc85e4..140e715 100644 --- a/ALObjectParser.Console/Program.cs +++ b/ALObjectParser.Console/Program.cs @@ -10,26 +10,18 @@ class Program static void Main(string[] args) { var path = args != null && args.Count() > 0 ? args[0] : @".\test_cu.al"; - var parser = new ALTestCodeunitParser(path); - var codeunit = parser.Read(); + var codeunit = ALParser.ReadSingle(path); Console.WriteLine($"Object info: {codeunit.Type} {codeunit.Id} {codeunit.Name}"); - Console.WriteLine($"Object path: {parser.Path}"); + Console.WriteLine($"Object path: {path}"); Console.WriteLine("-----------------------------------------------------------"); - foreach (var feature in codeunit.Features) + foreach (var method in codeunit.Methods) { - Console.WriteLine($"Test Feature: {feature.Name} including {feature.Scenarios.Count()} scenario(s)"); + Console.WriteLine($"Method: {method.Name} including {method.Parameters.Count()} pparameter(s)"); Console.WriteLine(); - foreach (var scenario in feature.Scenarios) + foreach (var param in method.Parameters) { - Console.WriteLine($" Test Scenario: #{scenario.ID} {scenario.Name}"); - - foreach (var element in scenario.Elements) - { - Console.WriteLine($" {element.Type}: {element.Value}"); - } - - Console.WriteLine(); + Console.WriteLine($" Parameter: #{param.Name} {param.Type}"); } Console.WriteLine("-----------------------------------------------------------"); } diff --git a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.dll b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.dll index 2b460bb..c83f819 100644 Binary files a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.dll and b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.dll differ diff --git a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.pdb b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.pdb index 37838da..451bccc 100644 Binary files a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.pdb and b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Cmd.pdb differ diff --git a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll index 9bb0376..1352230 100644 Binary files a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll and b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll differ diff --git a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb index e8069a3..8dc5b89 100644 Binary files a/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb and b/ALObjectParser.Console/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb differ diff --git a/ALObjectParser.Library/Enums/ScenarioElementType.cs b/ALObjectParser.Library/Enums/ScenarioElementType.cs deleted file mode 100644 index 9fb7418..0000000 --- a/ALObjectParser.Library/Enums/ScenarioElementType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public enum ScenarioElementType - { - FEATURE = 0, - SCENARIO, - GIVEN, - WHEN, - THEN - } -} diff --git a/ALObjectParser.Library/Helpers/ALMethodHelper.cs b/ALObjectParser.Library/Helpers/ALMethodHelper.cs index 9916825..983cc33 100644 --- a/ALObjectParser.Library/Helpers/ALMethodHelper.cs +++ b/ALObjectParser.Library/Helpers/ALMethodHelper.cs @@ -31,7 +31,7 @@ public static string Write(this ALMethod method) parameterTxt = String.Join(';', method.Parameters.Select(s => $"{(s.IsVar ? "var " : "")}{s.Name}: {s.Type}")); } - writer.WriteLine($"{(method.IsLocal ? "local " : "")}{method.MethodKind} {method.Name}({parameterTxt}){(!String.IsNullOrEmpty(method.ReturnType) ? ": " + method.ReturnType : "")}"); + writer.WriteLine($"{(method.IsLocal ? "local " : "")}{method.MethodKind} {(method.Name.Contains(" ") ? $"\"{method.Name}\"": method.Name)}({parameterTxt}){(!String.IsNullOrEmpty(method.ReturnType) ? ": " + method.ReturnType : "")}"); if (String.IsNullOrEmpty(method.Content)) { @@ -51,55 +51,5 @@ public static string Write(this ALMethod method) return result; } - - public static string Write(this ITestFeature feature) - { - return $"// [FEATURE] {feature.Name}"; - } - - public static string Write(this ITestScenario scenario) - { - return $"// [SCENARIO #{scenario.ID:0000}] {scenario.Name}"; - } - - public static string Write(this ITestScenarioElement element) - { - return $"// [{element.Type}] {element.Value}"; - } - - public static string WriteMethod(this ITestScenarioElement element, ALParserConfig config = null) - { - var prefix = ""; - switch (element.Type) - { - case ScenarioElementType.GIVEN: - prefix = config != null ? config.GivenFunctionPrefix : "Create"; - break; - case - ScenarioElementType.WHEN: - prefix = config != null ? config.WhenFunctionPrefix : "Assign"; - break; - case ScenarioElementType.THEN: - prefix = config != null ? config.ThenFunctionPrefix : "Verify"; - break; - default: - break; - } - - return $"{prefix}{element.Value.SanitizeName()}"; - } - - public static string SanitizeName(this string name) - { - var result = - String.Join("", - Regex - .Split(name, @"\W", RegexOptions.CultureInvariant) - .Where(s => !string.IsNullOrEmpty(s)) - .Select(s => Regex.Replace(s, "^.", m => m.Value.ToUpperInvariant())) - ); - - return result; - } } } diff --git a/ALObjectParser.Library/Helpers/TestFeatureComparer.cs b/ALObjectParser.Library/Helpers/TestFeatureComparer.cs deleted file mode 100644 index eb34023..0000000 --- a/ALObjectParser.Library/Helpers/TestFeatureComparer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestFeatureComparer : IEqualityComparer - { - public bool Equals(ITestFeature x, ITestFeature y) - { - return x.Name == y.Name && Enumerable.SequenceEqual(x.Scenarios, y.Scenarios, new TestScenarioComparer()); - } - - public int GetHashCode(ITestFeature obj) - { - return (obj.Name).GetHashCode(); - } - } -} diff --git a/ALObjectParser.Library/Helpers/TestFeatureNameComparer.cs b/ALObjectParser.Library/Helpers/TestFeatureNameComparer.cs deleted file mode 100644 index 7bc4928..0000000 --- a/ALObjectParser.Library/Helpers/TestFeatureNameComparer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestFeatureNameComparer : IEqualityComparer - { - public bool Equals(ITestFeature x, ITestFeature y) - { - return x.Name == y.Name; - } - - public int GetHashCode(ITestFeature obj) - { - return (obj.Name).GetHashCode(); - } - } -} diff --git a/ALObjectParser.Library/Helpers/TestScenarioComparer.cs b/ALObjectParser.Library/Helpers/TestScenarioComparer.cs deleted file mode 100644 index 7477c48..0000000 --- a/ALObjectParser.Library/Helpers/TestScenarioComparer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestScenarioComparer : IEqualityComparer - { - public bool Equals(ITestScenario x, ITestScenario y) - { - return x.Name == y.Name && x.ID == y.ID && Enumerable.SequenceEqual(x.Elements, y.Elements, new TestScenarioElementComparer()); - } - - public int GetHashCode(ITestScenario obj) - { - return ($"{obj.ID}{obj.Name}").GetHashCode(); - } - } -} diff --git a/ALObjectParser.Library/Helpers/TestScenarioElementComparer.cs b/ALObjectParser.Library/Helpers/TestScenarioElementComparer.cs deleted file mode 100644 index 9865aef..0000000 --- a/ALObjectParser.Library/Helpers/TestScenarioElementComparer.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestScenarioElementComparer : IEqualityComparer - { - public bool Equals(ITestScenarioElement x, ITestScenarioElement y) - { - return x.Type == y.Type && x.Value == y.Value; - } - - public int GetHashCode(ITestScenarioElement obj) - { - return ($"{obj.Type}{obj.Value}").GetHashCode(); - } - } -} diff --git a/ALObjectParser.Library/Helpers/TestScenarioIDComparer.cs b/ALObjectParser.Library/Helpers/TestScenarioIDComparer.cs deleted file mode 100644 index 87f7420..0000000 --- a/ALObjectParser.Library/Helpers/TestScenarioIDComparer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestScenarioIDComparer : IEqualityComparer - { - public bool Equals(ITestScenario x, ITestScenario y) - { - return x.ID == y.ID; - } - - public int GetHashCode(ITestScenario obj) - { - return ($"{obj.ID}{obj.Name}").GetHashCode(); - } - } -} diff --git a/ALObjectParser.Library/Interfaces/IALObject.cs b/ALObjectParser.Library/Interfaces/IALObject.cs index 1609e17..f932851 100644 --- a/ALObjectParser.Library/Interfaces/IALObject.cs +++ b/ALObjectParser.Library/Interfaces/IALObject.cs @@ -7,7 +7,8 @@ public interface IALObject int Id { get; set; } ALObjectType Type { get; set; } string Name { get; set; } - List Methods { get; set; } - List Features { get; set; } + ICollection Methods { get; set; } + ICollection Properties { get; set; } + ICollection Comments { get; set; } } } \ No newline at end of file diff --git a/ALObjectParser.Library/Interfaces/ITestFeature.cs b/ALObjectParser.Library/Interfaces/ITestFeature.cs deleted file mode 100644 index 9006030..0000000 --- a/ALObjectParser.Library/Interfaces/ITestFeature.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public interface ITestFeature - { - string Name { get; set; } - - ICollection Scenarios { get; set; } - } -} diff --git a/ALObjectParser.Library/Interfaces/ITestScenario.cs b/ALObjectParser.Library/Interfaces/ITestScenario.cs deleted file mode 100644 index c9c773e..0000000 --- a/ALObjectParser.Library/Interfaces/ITestScenario.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public interface ITestScenario - { - int ID { get; set; } - string Name { get; set; } - ITestFeature Feature { get; set; } - ICollection Elements { get; set; } - } -} diff --git a/ALObjectParser.Library/Interfaces/ITestScenarioElement.cs b/ALObjectParser.Library/Interfaces/ITestScenarioElement.cs deleted file mode 100644 index 86da97d..0000000 --- a/ALObjectParser.Library/Interfaces/ITestScenarioElement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public interface ITestScenarioElement - { - ScenarioElementType Type { get; set; } - string Value { get; set; } - } -} diff --git a/ALObjectParser.Library/Models/ALObject.cs b/ALObjectParser.Library/Models/ALObject.cs index 281701c..bd8f795 100644 --- a/ALObjectParser.Library/Models/ALObject.cs +++ b/ALObjectParser.Library/Models/ALObject.cs @@ -7,14 +7,16 @@ public class ALObject: IALObject public ALObject() { Methods = new List(); + Properties = new List(); + Comments = new List(); } public int Id { get; set; } public ALObjectType Type { get; set; } public string Name { get; set; } - public List Methods { get; set; } - public List Features { get; set; } - public IEnumerable Properties { get; set; } + public ICollection Methods { get; set; } + public ICollection Properties { get; set; } + public ICollection Comments { get; set; } } } \ No newline at end of file diff --git a/ALObjectParser.Library/Models/ALObjectParts/ALComment.cs b/ALObjectParser.Library/Models/ALObjectParts/ALComment.cs new file mode 100644 index 0000000..507c5ff --- /dev/null +++ b/ALObjectParser.Library/Models/ALObjectParts/ALComment.cs @@ -0,0 +1,9 @@ +namespace ALObjectParser.Library +{ + public class ALComment + { + public string Content { get; set; } + public int StartPos { get; set; } + public int EndPos { get; set; } + } +} \ No newline at end of file diff --git a/ALObjectParser.Library/Models/ALObjectParts/ALMethod.cs b/ALObjectParser.Library/Models/ALObjectParts/ALMethod.cs index d576bbc..02e8ece 100644 --- a/ALObjectParser.Library/Models/ALObjectParts/ALMethod.cs +++ b/ALObjectParser.Library/Models/ALObjectParts/ALMethod.cs @@ -8,6 +8,7 @@ public ALMethod() { Parameters = new List(); Attributes = new List(); + Comments = new List(); } public string Name { get; set; } @@ -16,8 +17,9 @@ public ALMethod() public bool IsLocal { get; set; } public ICollection Parameters { get; set; } public string ReturnType { get; set; } - public ITestScenario Scenario { get; set; } public string Content { get; set; } + public ALMethodBody MethodBody { get; set; } public ICollection Attributes { get; set; } + public IEnumerable Comments { get; set; } } } \ No newline at end of file diff --git a/ALObjectParser.Library/Models/ALObjectParts/ALMethodBody.cs b/ALObjectParser.Library/Models/ALObjectParts/ALMethodBody.cs new file mode 100644 index 0000000..7e771a7 --- /dev/null +++ b/ALObjectParser.Library/Models/ALObjectParts/ALMethodBody.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace ALObjectParser.Library +{ + public class ALMethodBody + { + public ALMethodBody() + { + Comments = new List(); + } + + public IEnumerable ContentLines { get; set; } + public string Content { get; set; } + public IEnumerable Comments { get; set; } + } +} \ No newline at end of file diff --git a/ALObjectParser.Library/Models/ALObjectTypeMap.cs b/ALObjectParser.Library/Models/ALObjectTypeMap.cs new file mode 100644 index 0000000..71704d0 --- /dev/null +++ b/ALObjectParser.Library/Models/ALObjectTypeMap.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ALObjectParser.Library +{ + public class ALObjectTypeMap: Dictionary + { + public ALObjectTypeMap() + { + Add(ALObjectType.table, typeof(ALTable)); + Add(ALObjectType.tableextension, typeof(ALTableExtension)); + Add(ALObjectType.page, typeof(ALPage)); + Add(ALObjectType.pagecustomization, typeof(ALPageCustomization)); + Add(ALObjectType.pageextension, typeof(ALPageExtension)); + Add(ALObjectType.report, typeof(ALTable)); + Add(ALObjectType.xmlport, typeof(ALTable)); + Add(ALObjectType.query, typeof(ALTable)); + Add(ALObjectType.codeunit, typeof(ALCodeunit)); + Add(ALObjectType.controladdin, typeof(ALTable)); + Add(ALObjectType.dotnet, typeof(ALTable)); + Add(ALObjectType.@enum, typeof(ALTable)); + Add(ALObjectType.profile, typeof(ALTable)); + } + + public static IALObject CreateInstance(ALObjectType type) + { + var items = new ALObjectTypeMap(); + dynamic instance = Activator.CreateInstance(items[type]); + + return instance; + } + } +} diff --git a/ALObjectParser.Library/Models/ALParserConfig.cs b/ALObjectParser.Library/Models/ALParserConfig.cs deleted file mode 100644 index afb1564..0000000 --- a/ALObjectParser.Library/Models/ALParserConfig.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public class ALParserConfig - { - public ALParserConfig() - { - GivenFunctionPrefix = "Create"; - WhenFunctionPrefix = "Assign"; - ThenFunctionPrefix = "Verify"; - } - - public int CodeunitId { get; set; } - public string CodeunitName { get; set; } - public string FilePath { get; set; } - public bool InitializeFunction { get; set; } - public string GivenFunctionPrefix { get; set; } - public string WhenFunctionPrefix { get; set; } - public string ThenFunctionPrefix { get; set; } - } -} diff --git a/ALObjectParser.Library/Models/TestMetadata/TestFeature.cs b/ALObjectParser.Library/Models/TestMetadata/TestFeature.cs deleted file mode 100644 index b876b3c..0000000 --- a/ALObjectParser.Library/Models/TestMetadata/TestFeature.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ALObjectParser.Library -{ - public class TestFeature : ITestFeature - { - public TestFeature() - { - Scenarios = new List(); - } - - public string Name { get; set; } - - public ICollection Scenarios { get; set; } - } -} diff --git a/ALObjectParser.Library/Models/TestMetadata/TestScenario.cs b/ALObjectParser.Library/Models/TestMetadata/TestScenario.cs deleted file mode 100644 index fbf3c63..0000000 --- a/ALObjectParser.Library/Models/TestMetadata/TestScenario.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - /// - /// Test Scenario object - /// - public class TestScenario : ITestScenario - { - /// - /// Default constructor - /// - public TestScenario() - { - Elements = new List(); - } - - public int ID { get; set; } - public string Name { get; set; } - public ITestFeature Feature { get; set; } - public ICollection Elements { get; set; } - } -} diff --git a/ALObjectParser.Library/Models/TestMetadata/TestScenarioElement.cs b/ALObjectParser.Library/Models/TestMetadata/TestScenarioElement.cs deleted file mode 100644 index d60dde5..0000000 --- a/ALObjectParser.Library/Models/TestMetadata/TestScenarioElement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ALObjectParser.Library -{ - public class TestScenarioElement: ITestScenarioElement - { - public ScenarioElementType Type { get; set; } - public string Value { get; set; } - } -} diff --git a/ALObjectParser.Library/Parsers/ALObjectParser.cs b/ALObjectParser.Library/Parsers/ALObjectParser.cs deleted file mode 100644 index dce5928..0000000 --- a/ALObjectParser.Library/Parsers/ALObjectParser.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; - -namespace ALObjectParser.Library -{ - /// - /// Read/Write AL Language formatted files - /// Base implementation that provides basic information processing - /// - public class ALObjectParser - { - #region Properties - - /// - /// Config object that can be passed from PowerShell/Commadline, etc.. - /// - public ALParserConfig Config { get; set; } - - /// - /// Current AL Object that is being processed - /// - public IALObject ALObject { get; set; } - - /// - /// File path of object to read from or write to - /// - public string Path { get; set; } - - #endregion - - #region Constructors - - /// - /// Base constructor - /// - public ALObjectParser() - { - ALObject = new ALObject(); - Config = new ALParserConfig(); - } - - /// - /// Constructor for PowerShell/Commadline - /// - /// Filesystem path of AL Object - public ALObjectParser(string FilePath): base() - { - ALObject = new ALObject(); - Config = new ALParserConfig(); - Path = FilePath; - } - - /// - /// Constructor for PowerShell/Commadline - /// Path is part of the config objectt in this case - /// - /// - public ALObjectParser(ALParserConfig config): base() - { - ALObject = new ALObject(); - Config = config; - Path = Config.FilePath; - } - - #endregion - - #region Read Object from file - - /// - /// Read File specified in "Path" property - /// - /// - public IALObject Read() - { - var Lines = File.ReadAllLines(this.Path); - return Read(Lines.ToList()); - } - - /// - /// Read File contents converted to String array - /// - /// Array of textlines - /// - public IALObject Read(List Lines) - { - GetObjectInfo(Lines, ALObject); - GetMethods(Lines, ALObject); - OnRead(Lines, ALObject); - - return ALObject; - } - - /// - /// Method to implement custom processing during parsing - /// - /// - /// - public virtual void OnRead(List Lines, IALObject Target) - { } - - /// - /// Basic object information, such as Type, ID, Name - /// - /// Array of textlines - /// Current ALObject instance - public void GetObjectInfo(List Lines, IALObject Target) - { - var pattern = @"([a-z]+)\s([0-9]+)\s(.*)"; - var line = Lines - .Where(w => Regex.IsMatch(w.ToLower(), pattern)) - .FirstOrDefault(); - - if (!string.IsNullOrEmpty(line)) - { - var items = Regex.Match(line, pattern); - var type = items.Groups[1].Value.ToEnum(); - - switch (type) - { - case ALObjectType.table: - ALObject = new ALTable(); - break; - case ALObjectType.tableextension: - ALObject = new ALTableExtension(); - break; - case ALObjectType.page: - ALObject = new ALPage(); - break; - case ALObjectType.pagecustomization: - ALObject = new ALPageCustomization(); - break; - case ALObjectType.pageextension: - ALObject = new ALPageExtension(); - break; - case ALObjectType.report: - break; - case ALObjectType.codeunit: - ALObject = new ALCodeunit(); - break; - case ALObjectType.xmlport: - break; - case ALObjectType.query: - break; - case ALObjectType.controladdin: - break; - case ALObjectType.@enum: - break; - case ALObjectType.dotnet: - break; - case ALObjectType.profile: - break; - default: - break; - } - - Target = ALObject; - - Target.Id = int.Parse(items.Groups[2].Value); - Target.Name = items.Groups[3].Value.Replace("\"", ""); - Target.Type = type; - } - - OnGetObjectInfo(line, Target); - } - - /// - /// Method to implement custom for extended classes - /// - /// Top line of object definition - /// Current ALObject instance - public virtual void OnGetObjectInfo(string Line, IALObject Target) - { } - - /// - /// Parse method of AL Object: triggers and procedures as well - /// - /// Array of textlines - /// Current ALObject instance - public void GetMethods(List Lines, IALObject Target) - { - var pattern = @"(procedure|trigger)\s+(.*?)\((.*?)\)\:?(.*)"; - var procedures = Lines - .Where(w => Regex.IsMatch(w, pattern)) - .ToList(); - - Target.Methods = procedures - .Select(s => - { - var method = new ALMethod(); - - method.IsLocal = s.Trim().StartsWith("local"); - var match = Regex.Match(s, pattern); - method.MethodKind = match.Groups[1].Value; - method.Name = match.Groups[2].Value; - - if (match.Groups.Count > 3) - { - var paramTxt = match.Groups[3].Value.Trim(); - if (!string.IsNullOrEmpty(paramTxt)) - { - method.Parameters = paramTxt.Split(';').Select(s => - { - var result = new ALParameter(); - var parts = s.Split(':'); - result.IsVar = parts[0].Trim().StartsWith("var "); - result.Name = parts[0].Replace("var ", "").Trim(); - result.Type = parts[1]; - - return result; - }).ToList(); - } - } - - if (match.Groups.Count > 4) - { - method.ReturnType = match.Groups[4].Value; - } - - // Get Method body from var|begin to end; - var start = Lines.IndexOf(s) + 1; - var nextLine = Lines.GetRange(start, Lines.Count - start - 1).FirstOrDefault(f => Regex.IsMatch(f, pattern)); - var end = Lines.IndexOf(nextLine); - if (end == -1) - { - end = Lines.Count; - } - var body = string.Join("\r\n", Lines.GetRange(start, end-start - 1)); - method.Content = body; - - // Check for Test Attribute - start = Lines.IndexOf(s) - 1; - var testMethod = Lines.ElementAt(start); - if (testMethod.ToLower().Contains("test")) - { - method.TestMethod = true; - } - - return method; - }) - .ToList(); - } - - #endregion - - #region Write Object to file - - /// - /// Generate a new filecontent from a TestFeature set - /// Prepared for PowerShell cmdlets - /// - /// TestFeature set to generate AL Methods - public void Write(List Features = null) - { - var objectTxt = Write(ALObject, Features); - File.WriteAllText(Path, objectTxt); - } - - /// - /// - /// - /// Current ALObject instance - /// TestFeature set to be merged with AL Methods - /// - public string Write(IALObject Target, List Features = null) - { - return OnWrite(Target, Features); - } - - /// - /// Extensible function - /// - /// Current ALObject instance - /// TestFeature set to be merge with AL Methods - /// - public virtual string OnWrite(IALObject Target, List Features = null) - { - var result = ""; - using (var stringWriter = new StringWriter()) - { - using (var writer = new IndentedTextWriter(stringWriter)) - { - OnWriteObjectHeader(writer, Target, Features); - OnWriteObjectMethods(writer, Target, Features); - OnWriteObjectFooter(writer, Target, Features); - } - - result = stringWriter.ToString(); - } - - return result; - } - - public virtual void OnWriteObjectHeader(IndentedTextWriter writer, IALObject Target, List Features = null) - { - writer.WriteLine($"{Target.Type} {Target.Id} {(Target.Name.Contains(' ') ? $"\"{Target.Name}\"" : Target.Name)}"); - writer.WriteLine("{"); - } - - public virtual void OnWriteObjectMethods(IndentedTextWriter writer, IALObject Target, List Features = null) - { - var methods = Target.Methods.Select(method => OnWriteObjectMethod(Target, method)); - var methodTxt = String.Join("\r\n\r\n ", methods); - - writer.Indent++; - writer.WriteLine(methodTxt); - writer.Indent--; - } - - public virtual void OnWriteObjectFooter(IndentedTextWriter writer, IALObject Target, List Features = null) - { - writer.WriteLine("}"); - } - - public virtual string OnWriteObjectMethod(IALObject Target, ALMethod method) - { - return method.Write(); - } - - #endregion - } -} diff --git a/ALObjectParser.Library/Parsers/ALParser.cs b/ALObjectParser.Library/Parsers/ALParser.cs new file mode 100644 index 0000000..17db0ce --- /dev/null +++ b/ALObjectParser.Library/Parsers/ALParser.cs @@ -0,0 +1,106 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace ALObjectParser.Library +{ + /// + /// Read/Write AL Language formatted files + /// Base implementation that provides basic information processing + /// + public static class ALParser + { + public static IEnumerable Read(string Path) + { + return ALParser.Read(Path); + } + + public static IEnumerable ReadObjectInfos(string Path) + { + return ALParser.ReadObjectInfos(Path); + } + + public static IALObject ReadSingle(string Path) + { + return ALParser.ReadSingle(Path); + } + + public static IEnumerable Read(string Path) + where T: ALObjectReaderBase, new() + { + var reader = new T(); + var result = reader.Read(Path); + + return result; + } + + public static IEnumerable ReadObjectInfos(string Path) + where T : ALObjectReaderBase, new() + { + var reader = new T(); + var result = reader.ReadObjectInfos(Path); + + return result; + } + + public static IALObject ReadSingle(string Path) + where T : ALObjectReaderBase, new() + { + var reader = new T(); + var result = reader.ReadSingle(Path); + + return result; + } + + public static void Write(IALObject Target, string Path) + { + ALParser.Write(Target, Path); + } + + public static void Write(IEnumerable Target, string Path) + { + ALParser.Write(Target, Path); + } + + public static string Write(IALObject Target) + { + return ALParser.Write(Target); + } + + public static string Write(IEnumerable Target) + { + return ALParser.Write(Target); + } + + public static void Write(IALObject Target, string Path) + where T : ALObjectWriterBase, new() + { + var writer = new T(); + writer.Write(Target, Path); + } + + public static void Write(IEnumerable Target, string Path) + where T : ALObjectWriterBase, new() + { + var writer = new T(); + writer.Write(Target, Path); + } + + public static string Write(IALObject Target) + where T : ALObjectWriterBase, new() + { + var writer = new T(); + return writer.Write(Target); + } + + public static string Write(IEnumerable Target) + where T : ALObjectWriterBase, new() + { + var writer = new T(); + return writer.Write(Target); + } + } +} diff --git a/ALObjectParser.Library/Parsers/ALTestCodeunitParser.cs b/ALObjectParser.Library/Parsers/ALTestCodeunitParser.cs deleted file mode 100644 index c428b6d..0000000 --- a/ALObjectParser.Library/Parsers/ALTestCodeunitParser.cs +++ /dev/null @@ -1,358 +0,0 @@ -using System; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; - -namespace ALObjectParser.Library -{ - public class ALTestCodeunitParser : ALObjectParser - { - public ALTestCodeunitParser(): base() - { - ALObject = new ALCodeunit(); - } - - public ALTestCodeunitParser(string FilePath) : base(FilePath) - { - ALObject = new ALCodeunit(); - Path = FilePath; - } - - public ALTestCodeunitParser(ALParserConfig config) : base(config) - { - ALObject = new ALCodeunit(); - } - - #region Read from Object - - public override void OnRead(List Lines, IALObject Target) - { - if (Target.Methods == null) - return; - - if (Target.Methods.Count == 0) - return; - - var testMethods = Target.Methods.Where(w => w.TestMethod == true).ToList(); - var pattern = @"\[([aA-zZ]+)(.*)\]\s+(.*)"; - var features = new List(); - - foreach (var method in testMethods) - { - var matches = Regex.Matches(method.Content, pattern); - if (matches.Count > 0) - { - var matchList = matches.ToList(); - var scenarioElems = matchList - .Select(m => new { - Type = m.Groups[1].Value.ToEnum(), - Id = m.Groups[2].Value.Trim().Replace("#", ""), - Name = m.Groups[3].Value.Trim() - }); - - ITestFeature feature = new TestFeature(); - var scenario = new TestScenario(); - - foreach (var elem in scenarioElems) - { - switch (elem.Type) - { - case ScenarioElementType.FEATURE: - feature = features.FirstOrDefault(a => a.Name == elem.Name); - if (feature == null) - { - feature = new TestFeature { - Name = elem.Name, - Scenarios = new List() - }; - features.Add(feature); - } - break; - case ScenarioElementType.SCENARIO: - scenario = new TestScenario(); - scenario.ID = int.Parse(elem.Id); - scenario.Name = elem.Name; - scenario.Feature = feature; - feature.Scenarios.Add(scenario); - break; - case ScenarioElementType.GIVEN: - var given = new TestScenarioElement(); - given.Type = elem.Type; - given.Value = elem.Name; - scenario.Elements.Add(given); - break; - case ScenarioElementType.WHEN: - var when = new TestScenarioElement(); - when.Type = elem.Type; - when.Value = elem.Name; - scenario.Elements.Add(when); - break; - case ScenarioElementType.THEN: - var then = new TestScenarioElement(); - then.Type = elem.Type; - then.Value = elem.Name; - scenario.Elements.Add(then); - break; - default: - break; - } - } - - method.Scenario = scenario; - } - } - - Target.Features = features; - } - - #endregion - - #region Write to Object - - public override void OnWriteObjectHeader(IndentedTextWriter writer, IALObject Target, List Features = null) - { - base.OnWriteObjectHeader(writer, Target, Features); - writer.Indent++; - writer.WriteLine("SubType = Test;"); - writer.WriteLine(); - writer.Indent--; - } - - public override void OnWriteObjectMethods(IndentedTextWriter writer, IALObject Target, List Features = null) - { - if (Features != null && Features.Count() > 0) - { - if (Target.Methods.Count > 0) - { - MergeFeatures(Target, Features); - } - else - { - FeaturesToMethods(Target, Features); - } - } - - base.OnWriteObjectMethods(writer, Target, Features); - } - - public override string OnWriteObjectMethod(IALObject Target, ALMethod method) - { - var result = ""; - using (var stringWriter = new StringWriter()) - { - using (var writer = new IndentedTextWriter(stringWriter)) - { - writer.Indent++; - writer.WriteLine(); - - WriteObjectMethodHeader(method, writer); - WriteObjectMethodBody(Target, method, writer); - WriteObjectMethodFooter(method, writer); - - writer.Indent--; - - result = stringWriter.ToString().Replace("}", "").Trim(); - } - } - - return result; - } - - public void WriteObjectMethodHeader(ALMethod method, IndentedTextWriter writer) - { - bool HasScenario = method.Scenario != null; - if (HasScenario) - { - writer.WriteLine($"//#region [SCENARIO #{method.Scenario.ID:0000}] {method.Scenario.Name}"); - writer.WriteLine(); - } - - if (method.TestMethod) - { - writer.WriteLine("[Test]"); - } - - var parameterTxt = ""; - if (method.Parameters.Count > 0) - { - parameterTxt = String.Join(';', method.Parameters.Select(s => $"{(s.IsVar ? "var " : "")}{s.Name}: {s.Type}")); - } - - writer.WriteLine($"{(method.IsLocal ? "local " : "")}{method.MethodKind} {method.Name}({parameterTxt}){(!String.IsNullOrEmpty(method.ReturnType) ? ": " + method.ReturnType : "")}"); - } - - public void WriteObjectMethodBody(IALObject Target, ALMethod method, IndentedTextWriter writer) - { - bool HasScenario = method.Scenario != null; - bool NoContent = String.IsNullOrEmpty(method.Content); - - if (NoContent) - { - if (HasScenario) - { - writer.WriteLine(method.Scenario.Feature.Write()); - } - - writer.WriteLine("begin"); - - if (HasScenario) - { - writer.Indent++; - - writer.WriteLine(method.Scenario.Write()); - writer.WriteLine("Initialize();"); - if (method.Scenario.Elements != null) - { - writer.WriteLine(); - method.Scenario - .Elements - .OrderBy(o => o.Type) - .ToList() - .ForEach(e => { - writer.WriteLine(e.Write()); - writer.WriteLine(e.WriteMethod(Config) + "();"); - writer.WriteLine(); - }); - } - - writer.Indent--; - } - - writer.WriteLine("end;"); - - method.Scenario - .Elements - .OrderBy(o => o.Type) - .ToList() - .ForEach(e => - { - if (!Target.Methods.Any(a => a.Name == e.WriteMethod(Config))) - { - writer.WriteLine(); - writer.WriteLine($"local procedure {e.WriteMethod(Config)}()"); - writer.WriteLine("begin"); - writer.WriteLine("end;"); - } - }); - } - else - { - writer.WriteLine(method.Content); - } - } - - public void WriteObjectMethodFooter(ALMethod method, IndentedTextWriter writer) - { - bool HasScenario = method.Scenario != null; - if (HasScenario) - { - writer.WriteLine(); - writer.WriteLine("//#endregion"); - } - } - - #endregion - - #region Merge Feature-sets or create a new set - - public void FeaturesToMethods(IALObject Target, List Features = null) - { - if (Features == null) - return; - - if (Features.Count == 0) - return; - - Target.Methods.AddRange(Features - .SelectMany(s => s.Scenarios) - .Select(s => new ALMethod() - { - Name = s.Name.SanitizeName(), - TestMethod = true, - Scenario = s, - MethodKind = "procedure", - Content = "" - }) - .ToList() - ); - } - - public void MergeFeatures(IALObject Target, List Features = null) - { - if (Features == null) - return; - - if (Features.Count == 0) - return; - - var identical = Target.Features.SequenceEqual(Features, new TestFeatureComparer()); - if (identical) - { - return; - } - - // add new features - var newFeatures = Features.Except(Target.Features, new TestFeatureNameComparer()).ToList(); - if (newFeatures.Count() > 0) - { - Target.Features.AddRange(newFeatures); - - FeaturesToMethods(Target, newFeatures); - } - - // check same feature for new scenarios - foreach(var feature in Target.Features) - { - var UpdatedFeature = Features.FirstOrDefault(f => f.Name == feature.Name); - if (UpdatedFeature != null) - { - var newScenarios = UpdatedFeature.Scenarios.Except(feature.Scenarios, new TestScenarioIDComparer()).ToList(); - if (newScenarios.Count > 0) - { - (feature.Scenarios as List).AddRange(newScenarios); - Target.Methods.AddRange(newScenarios - .Select(s => new ALMethod() - { - Name = s.Name.SanitizeName(), - TestMethod = true, - Scenario = s, - MethodKind = "procedure", - Content = "" - }) - .ToList() - ); - } - } - } - - // check existing scenarios for updates - var CurrentScenarios = Target.Features.SelectMany(s => s.Scenarios).ToList(); - var UpdatedScenarios = Features.SelectMany(s => s.Scenarios).ToList(); - - foreach (var scenario in CurrentScenarios) - { - var UpdatedScenario = UpdatedScenarios - .Where(w => w.Feature.Name == scenario.Feature.Name && w.ID == scenario.ID) - .FirstOrDefault(); - - if (UpdatedScenario != null) - { - scenario.Name = UpdatedScenario.Name; - scenario.ID = UpdatedScenario.ID; - scenario.Elements = UpdatedScenario.Elements.ToList(); - - var method = Target.Methods.Where(w => w.Scenario == scenario).FirstOrDefault(); - if (method != null) - { - method.Scenario = UpdatedScenario; - method.Content = ""; //TODO!! Update content instead of recreation - } - } - } - } - - #endregion - } -} diff --git a/ALObjectParser.Library/Readers/ALObjectReaderBase.cs b/ALObjectParser.Library/Readers/ALObjectReaderBase.cs new file mode 100644 index 0000000..4d123f9 --- /dev/null +++ b/ALObjectParser.Library/Readers/ALObjectReaderBase.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ALObjectParser.Library +{ + public class ALObjectReaderBase + { + public string ObjectHeaderPattern { get; set; } + + public ALObjectReaderBase() + { + ObjectHeaderPattern = @"^([a-z]+)\s(?(1)([0-9]+|))(.*)"; + } + + #region Read Object from file + + public IEnumerable Read(string Path) + { + var Lines = File.ReadAllLines(Path); + var splittedLines = SplitObjectLines(Lines); + + var result = new List(); + foreach (var objLines in splittedLines) + { + var obj = Read(objLines); + result.Add(obj); + } + + return result; + } + + public IEnumerable ReadObjectInfos(string Path) + { + var Lines = File.ReadAllLines(Path); + var headerLines = GetObjectHeaderLines(Lines); + + var result = new List(); + foreach (var header in headerLines) + { + IALObject Target; + GetObjectInfo(header, out Target); + result.Add(Target); + } + + return result; + } + + /// + /// Read File specified in "Path" property + /// + /// + public IALObject ReadSingle(string Path) + { + var Lines = File.ReadAllLines(Path); + return Read(Lines); + } + + public T Read(string Path) + where T: ALObject + { + var Lines = File.ReadAllLines(Path); + IALObject result = Read(Lines); + + return (result as T); + } + + /// + /// Read File contents converted to String array + /// + /// Array of textlines + /// + public IALObject Read(IEnumerable Lines) + { + IALObject Target; + GetObjectInfo(Lines, out Target); + GetMethods(Lines, Target); + GetComments(Lines, Target); + GetObjectProperties(Lines, Target); + OnRead(Lines, Target); + + return Target; + } + + /// + /// Method to implement custom processing during parsing + /// + /// + /// + public virtual void OnRead(IEnumerable Lines, IALObject Target) + { } + + public IEnumerable> SplitObjectLines(IEnumerable Lines) + { + var contents = Lines.ToList(); + var headerLines = GetObjectHeaderLines(contents); + var headers = headerLines + .Select(s => contents.IndexOf(s)) + .ToList(); + + if (headers.Count() < 2) + { + return new List>() { Lines }; + } + + var result = new List>(); + var c = headers.Count(); + for (int i = 0; i < c; i++) + { + var startIndex = headers[i]; + var endIndex = Lines.Count()-1; + var j = i + 1; + if (j < c) + { + endIndex = headers[j]; + } + + result.Add(contents.GetRange(startIndex, endIndex-startIndex)); + } + + return result; + } + + public IEnumerable GetObjectHeaderLines(IEnumerable Lines) + { + var headers = Lines + .Where(w => Regex.IsMatch(w.ToLower(), ObjectHeaderPattern)); + + return headers; + } + + /// + /// Basic object information, such as Type, ID, Name + /// + /// Array of textlines + /// Current ALObject instance + public void GetObjectInfo(IEnumerable Lines, out IALObject Target) + { + Target = new ALObject(); + var line = Lines + .Where(w => Regex.IsMatch(w.ToLower(), ObjectHeaderPattern)) + .FirstOrDefault(); + + GetObjectInfo(line, out Target); + } + + /// + /// Basic object information, such as Type, ID, Name + /// + /// Array of textlines + /// Current ALObject instance + public void GetObjectInfo(string line, out IALObject Target) + { + Target = new ALObject(); + + if (!string.IsNullOrEmpty(line)) + { + var items = Regex.Match(line, ObjectHeaderPattern); + var type = items.Groups[1].Value.ToEnum(); + var idTxt = items.Groups[2].Value; + + Target = ALObjectTypeMap.CreateInstance(type); + Target.Id = 0; + if (!String.IsNullOrEmpty(idTxt)) + { + Target.Id = int.Parse(items.Groups[2].Value); + } + Target.Name = items.Groups[3].Value.Replace("\"", "").Trim(); + Target.Type = type; + } + + OnGetObjectInfo(line, Target); + } + + /// + /// Method to implement custom for extended classes + /// + /// Top line of object definition + /// Current ALObject instance + public virtual void OnGetObjectInfo(string Line, IALObject Target) + { } + + public void GetObjectProperties(IEnumerable Lines, IALObject Target) + { + var firstMatch = false; + var pattern = @"\s+(.*?)\s+\=\s+(.*)\;$"; + foreach (var line in Lines) + { + if (Regex.IsMatch(line, pattern)) + { + if (!firstMatch) + { + firstMatch = true; + } + + OnGetObjectProperty(line, Target, pattern); + } + else + { + if (firstMatch) + { + break; + } + } + } + } + + public virtual void OnGetObjectProperty(string Line, IALObject Target, string pattern) + { + var match = Regex.Match(Line, pattern); + + if (match.Groups.Count > 1) + { + var prop = new ALProperty { Name = match.Groups[1].Value, Value = match.Groups[2].Value }; + Target.Properties.Add(prop); + } + } + + /// + /// Parse method of AL Object: triggers and procedures as well + /// + /// Array of textlines + /// Current ALObject instance + public void GetMethods(IEnumerable Lines, IALObject Target) + { + var pattern = @"^\s{0,4}(local|procedure|trigger)\s+(.*?)\((.*?)\)\:?(.*)"; + var procedures = Lines + .Where(w => Regex.IsMatch(w, pattern)) + .ToList(); + + if (procedures.Count() == 0) + { + return; + } + + Target.Methods = procedures + .Select(s => + { + var method = new ALMethod(); + + method.IsLocal = s.Trim().StartsWith("local"); + var match = Regex.Match(s, pattern); + method.MethodKind = match.Groups[1].Value; + method.Name = match.Groups[2].Value; + + if (match.Groups.Count > 3) + { + var paramTxt = match.Groups[3].Value.Trim(); + if (!string.IsNullOrEmpty(paramTxt)) + { + method.Parameters = paramTxt.Split(';').Select(s => + { + var result = new ALParameter(); + var parts = s.Split(':'); + result.IsVar = parts[0].Trim().StartsWith("var "); + result.Name = parts[0].Replace("var ", "").Trim(); + result.Type = parts[1]; + + return result; + }).ToList(); + } + } + + if (match.Groups.Count > 4) + { + method.ReturnType = match.Groups[4].Value; + } + + // Get Method body from var|begin to end; + var txtLines = Lines.ToList(); + var start = txtLines.IndexOf(s) + 1; + var nextLine = txtLines.GetRange(start, txtLines.Count() - start - 1).FirstOrDefault(f => Regex.IsMatch(f, pattern)); + var end = txtLines.IndexOf(nextLine); + if (end == -1) + { + end = Lines.Count(); + } + + var bodyLines = txtLines.GetRange(start, end - start - 1); + var body = string.Join("\r\n", bodyLines); + var comments = GetComments(bodyLines); + method.MethodBody = new ALMethodBody + { + Comments = comments, + Content = body, + ContentLines = bodyLines + }; + + method.Content = body; + + // Check for Test Attribute + start = txtLines.IndexOf(s) - 1; + var testMethod = Lines.ElementAt(start); + if (testMethod.ToLower().Contains("test")) + { + method.TestMethod = true; + } + + return method; + }) + .ToList(); + } + + public void GetComments(IEnumerable Lines, IALObject Target) + { + var comments = GetComments(Lines); + Target.Comments = comments; + } + + public ICollection GetComments(IEnumerable Lines) + { + var pattern = @"\/\/"; + var comments = new List(); + var c = Lines.Count(); + + for (int i = 0; i < c; i++) + { + var line = Lines.ElementAt(i); + if (Regex.IsMatch(line, pattern)) { + + var comment = new ALComment + { + Content = line, + StartPos = i, + EndPos = i + }; + comments.Add(comment); + } + } + + return comments; + } + + #endregion + } +} diff --git a/ALObjectParser.Library/Writers/ALObjectWriterBase.cs b/ALObjectParser.Library/Writers/ALObjectWriterBase.cs new file mode 100644 index 0000000..77657e4 --- /dev/null +++ b/ALObjectParser.Library/Writers/ALObjectWriterBase.cs @@ -0,0 +1,106 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace ALObjectParser.Library +{ + public class ALObjectWriterBase + { + #region Write Object to file + + /// + /// Generate a new filecontent from IALObject + /// + /// + /// + public void Write(IEnumerable Target, string Path) + { + var objectTxt = Write(Target); + File.WriteAllText(Path, objectTxt); + } + + public string Write(IEnumerable Target) + { + var objectTxts = Target.Select(s => Write(s)); + var objectTxt = string.Join($"{Environment.NewLine}", objectTxts); + + return objectTxt; + } + + /// + /// Generate a new filecontent from IALObject + /// + /// + /// + public void Write(IALObject Target, string Path) + { + var objectTxt = Write(Target); + File.WriteAllText(Path, objectTxt); + } + + /// + /// + /// + /// Current ALObject instance + /// TestFeature set to be merged with AL Methods + /// + public string Write(IALObject Target) + { + return OnWrite(Target); + } + + /// + /// Extensible function + /// + /// Current ALObject instance + /// + public virtual string OnWrite(IALObject Target) + { + var result = ""; + using (var stringWriter = new StringWriter()) + { + using (var writer = new IndentedTextWriter(stringWriter)) + { + OnWriteObjectHeader(writer, Target); + OnWriteObjectMethods(writer, Target); + OnWriteObjectFooter(writer, Target); + } + + result = stringWriter.ToString(); + } + + return result; + } + + public virtual void OnWriteObjectHeader(IndentedTextWriter writer, IALObject Target) + { + writer.WriteLine($"{Target.Type} {Target.Id} {(Target.Name.Contains(' ') ? $"\"{Target.Name}\"" : Target.Name)}"); + writer.WriteLine("{"); + } + + public virtual void OnWriteObjectMethods(IndentedTextWriter writer, IALObject Target) + { + var methods = Target.Methods.Select(method => OnWriteObjectMethod(Target, method)); + var methodTxt = String.Join("\r\n\r\n ", methods); + + writer.Indent++; + writer.WriteLine(methodTxt); + writer.Indent--; + } + + public virtual void OnWriteObjectFooter(IndentedTextWriter writer, IALObject Target) + { + writer.WriteLine("}"); + } + + public virtual string OnWriteObjectMethod(IALObject Target, ALMethod method) + { + return method.Write(); + } + + #endregion + } +} diff --git a/ALObjectParser.Library/bin/Debug/ALObjectParser.Library.1.0.0.nupkg b/ALObjectParser.Library/bin/Debug/ALObjectParser.Library.1.0.0.nupkg index 36487fa..8a778bd 100644 Binary files a/ALObjectParser.Library/bin/Debug/ALObjectParser.Library.1.0.0.nupkg and b/ALObjectParser.Library/bin/Debug/ALObjectParser.Library.1.0.0.nupkg differ diff --git a/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll b/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll index 9bb0376..1352230 100644 Binary files a/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll and b/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.dll differ diff --git a/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb b/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb index e8069a3..8dc5b89 100644 Binary files a/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb and b/ALObjectParser.Library/bin/Debug/netcoreapp3.0/ALObjectParser.Library.pdb differ diff --git a/ALObjectParser.Tests/ReaderTests.cs b/ALObjectParser.Tests/ReaderTests.cs index b562189..61b300a 100644 --- a/ALObjectParser.Tests/ReaderTests.cs +++ b/ALObjectParser.Tests/ReaderTests.cs @@ -8,26 +8,37 @@ namespace ALObjectParser.Tests public class ReaderTests: TestBase { [Test] - public void TestCodeunit_ID_Name() + public void Read_ID_Name() { - var result = parser.Read(lines); + var result = ALParser.Read(testPath); - Assert.AreEqual(81000, result.Id); - Assert.AreEqual(@"LookupValue UT Customer", result.Name); + Assert.AreEqual(result.Count(), 2); + Assert.AreEqual(81000, result.ElementAt(1).Id); + Assert.AreEqual(@"LookupValue UT Customer", result.ElementAt(1).Name); } [Test] - public void TestCodeunit_Verify_Procedures() + public void Read_ObjectHeaders() { - var result = parser.Read(lines); + var result = ALParser.ReadObjectInfos(testPath); + + Assert.AreEqual(result.Count(), 2); + Assert.AreEqual(81000, result.ElementAt(1).Id); + Assert.AreEqual(@"LookupValue UT Customer", result.ElementAt(1).Name); + } + + [Test] + public void Read_Verify_Procedures() + { + var result = ALParser.ReadSingle(testPath); Assert.IsTrue(result.Methods.Count > 0); } [Test] - public void TestCodeunit_Procedure_Verify_Parameters() + public void Read_Procedure_Verify_Parameters() { - var result = parser.Read(lines); + var result = ALParser.ReadSingle(testPath); Assert.IsTrue(result.Methods.First().Parameters.Count > 0); } @@ -35,41 +46,48 @@ public void TestCodeunit_Procedure_Verify_Parameters() [Test] [TestCase(0, false)] // Has Return Type [TestCase(1, true)] // Does not have Return Type - public void TestCodeunit_Procedure_Verify_ReturnType(int index, bool expected) + public void Read_Procedure_Verify_ReturnType(int index, bool expected) { - var result = parser.Read(lines); - var actual = string.IsNullOrEmpty(result.Methods[index].ReturnType.Trim()) == expected; + var result = ALParser.ReadSingle(testPath); + var actual = string.IsNullOrEmpty(result.Methods.ElementAt(index).ReturnType.Trim()) == expected; Assert.IsTrue(actual); } [Test] - public void TestCodeunit_Procedure_Verify_TestAttribute() + public void Read_Procedure_Verify_TestAttribute() { - var result = parser.Read(lines); - + var result = ALParser.ReadSingle(testPath); Assert.IsTrue(result.Methods.First().TestMethod); } [Test] [TestCase(0, false)] [TestCase(12, true)] - public void TestCodeunit_Procedure_Verify_IsLocal(int index, bool expected) + public void Read_Procedure_Verify_IsLocal(int index, bool expected) { - var result = parser.Read(lines); - var actual = result.Methods[index].IsLocal == expected; + var result = ALParser.ReadSingle(testPath); + var actual = result.Methods.ElementAt(index).IsLocal == expected; Assert.IsTrue(actual); } [Test] - public void TestCodeunit_Verify_TestFeaturesAndScenarios() + public void Read_Comments_Object() + { + var result = ALParser.Read(testPath); + var actual = result.ElementAt(1).Comments; + + Assert.IsTrue(actual.Count() > 0); + } + + [Test] + public void Read_Comments_Methods() { - var result = parser.Read(lines); + var result = ALParser.Read(testPath); + var actual = result.ElementAt(1).Methods.FirstOrDefault(f => f.Name == "CheckThatLabelCanBeAssignedToCustomer"); - // There should be 1 Feature + 3 Scenarios - Assert.IsTrue(result.Features.Count == 1); - Assert.IsTrue(result.Features.SelectMany(s => s.Scenarios).Count() == 3); + Assert.IsTrue(actual.MethodBody.Comments.Count() == 6); } } diff --git a/ALObjectParser.Tests/TestBase.cs b/ALObjectParser.Tests/TestBase.cs index a542031..83cc616 100644 --- a/ALObjectParser.Tests/TestBase.cs +++ b/ALObjectParser.Tests/TestBase.cs @@ -9,155 +9,13 @@ namespace ALObjectParser.Tests { public class TestBase { - protected string testFileContent; - protected ALTestCodeunitParser parser; + protected string testPath; protected List lines; [SetUp] public void Setup() { - #region Test File - this.testFileContent = @" -codeunit 81000 ""LookupValue UT Customer"" -{ - // Generated on 2019. 09. 28. at 22:11 by MártonSági - - // [FEATURE] LookupValue UT Customer - SubType = Test; - - - [Test] - procedure CheckThatLabelCanBeAssignedToCustomer(var Rec: Record ""Sales Header""): Boolean - // [FEATURE] LookupValue UT Customer - begin - // [SCENARIO #0001] Check that label can be assigned to customer - Initialize(); - - // [GIVEN] A label - CreateALabel(); - - // [GIVEN] A customer - if this then begin - - CreateACustomer(); - end; - - // [WHEN] Assign label to customer - AssignLabelToCustomer(); - - // [THEN] Customer has label field populated - VerifyCustomerHasLabelFieldPopulated(); - - end; - - [Test] - procedure CheckThatLabelFieldTableRelationIsValidatedForNonExistingLabelOnCustomer() - // [FEATURE] LookupValue UT Customer - begin - // [SCENARIO #0002] Check that label field table relation is validated for non-existing label on customer - Initialize(); - - // [GIVEN] A non-existing label value - CreateANonExistingLabelValue(); - - // [GIVEN] A customer record variable - CreateACustomerRecordVariable(); - - // [WHEN] Assign non-existing label to customer - AssignNonExistingLabelToCustomer(); - - // [THEN] Non existing label error was thrown - VerifyNonExistingLabelErrorWasThrown(); - - end; - - [Test] - procedure CheckThatLabelCanBeAssignedOnCustomerCard() - // [FEATURE] LookupValue UT Customer - begin - // [SCENARIO #0003] Check that label can be assigned on customer card - Initialize(); - - // [GIVEN] A label - CreateALabel(); - - // [GIVEN] A customer card - CreateACustomerCard(); - - // [WHEN] Assign label to customer card - AssignLabelToCustomerCard(); - - // [THEN] Customer has label field populated - VerifyCustomerHasLabelFieldPopulated(); - - end; - - var - IsInitialized: Boolean; - - local procedure Initialize() - var - LibraryTestInitialize: Codeunit ""Library - Test Initialize""; - begin - LibraryTestInitialize.OnTestInitialize(Codeunit::""LookupValue UT Customer""); - - if IsInitialized then - exit; - - LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::""LookupValue UT Customer""); - - IsInitialized := true; - Commit(); - - LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::""LookupValue UT Customer""); - end; - - local procedure AssignLabelToCustomer() - begin - end; - - local procedure AssignLabelToCustomerCard() - begin - end; - - local procedure AssignNonExistingLabelToCustomer() - begin - end; - - local procedure CreateACustomer() - begin - end; - - local procedure CreateACustomerCard() - begin - end; - - local procedure CreateACustomerRecordVariable() - begin - end; - - local procedure CreateALabel() - begin - end; - - local procedure CreateANonExistingLabelValue() - begin - end; - - local procedure VerifyCustomerHasLabelFieldPopulated() - begin - end; - - local procedure VerifyNonExistingLabelErrorWasThrown() - begin - end; - - } -"; - #endregion - - this.parser = new ALTestCodeunitParser(); - this.lines = testFileContent.Split("\r\n").ToList(); + testPath = @".\test_cu.al"; } } } diff --git a/ALObjectParser.Tests/WriterTests.cs b/ALObjectParser.Tests/WriterTests.cs index 56dea30..a114c5c 100644 --- a/ALObjectParser.Tests/WriterTests.cs +++ b/ALObjectParser.Tests/WriterTests.cs @@ -5,24 +5,32 @@ namespace ALObjectParser.Tests { + public class WriterTests : TestBase { [Test] public void WriteBackExistingObject_NoChange() { - var alobject = parser.Read(lines); - var result = parser.Write(alobject); + var alobjects = ALParser.Read(testPath); + foreach (var obj in alobjects) + { + var result = ALParser.Write(obj); + Assert.IsNotEmpty(result); + } - Assert.IsNotEmpty(result); + var allobjStr = ALParser.Write(alobjects); + Assert.IsNotEmpty(allobjStr); } + [Test] public void WriteBackExistingObject_UpdatedParameter() { - var alobject = parser.Read(lines); + var alobjects = ALParser.Read(testPath); + var alobject = alobjects.ElementAt(1); alobject.Methods.ElementAt(0).Parameters.ElementAt(0).Name = "UpdatedParameter_NewNameGiven"; - var result = parser.Write(alobject); + var result = ALParser.Write(alobjects); Assert.IsNotEmpty(result); Assert.IsTrue(result.Contains("UpdatedParameter_NewNameGiven")); @@ -35,24 +43,19 @@ public void WriteNewObject_FromALObjectClass() { Id = 81000, Name = "Test Codeunit", - Features = new List(), Methods = new List() }; - var features = GetFeatures(); - alobject.Features = features; - var scenario = features.ElementAt(0).Scenarios.ElementAt(0); - - var method = new ALMethod { TestMethod = true, Name = "Test Method", MethodKind = "procedure", Scenario = scenario }; + var method = new ALMethod { TestMethod = true, Name = "TestMethod", MethodKind = "procedure" }; alobject.Methods.Add(method); - var result = parser.Write(alobject); + var result = ALParser.Write(alobject); Assert.IsNotEmpty(result); } - [Test] + /*[Test] public void WriteNewObject_FromFeatures() { var alobject = new ALCodeunit @@ -199,6 +202,7 @@ private List GetFeatures() features.Add(feature); return features; - } + }*/ } + } \ No newline at end of file diff --git a/ALObjectParser.Tests/test_cu.al b/ALObjectParser.Tests/test_cu.al index 2f59c72..f48b90b 100644 --- a/ALObjectParser.Tests/test_cu.al +++ b/ALObjectParser.Tests/test_cu.al @@ -1,4 +1,37 @@ -codeunit 81000 "LookupValue UT Customer" +page 88971 "ATDDTestFeatures_DSK" +{ + Caption = 'ATDD Test Features'; + PageType = List; + SourceTable = "ATDDTestFeature_DSK"; + UsageCategory = Lists; + ApplicationArea = All; + + layout + { + area(content) + { + repeater(Group) + { + + field("Code"; "Code") + { + ApplicationArea = All; + //Caption = 'Code'; + } + + field("Name"; "Name") + { + ApplicationArea = All; + //Caption = 'Name'; + } + + } + } + } + +} + +codeunit 81000 "LookupValue UT Customer" { // Generated on 2019. 09. 28. at 22:11 by MártonSági diff --git a/Nuget.config b/Nuget.config new file mode 100644 index 0000000..668c44c --- /dev/null +++ b/Nuget.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file