| 
1 | 1 | using FineCodeCoverage.Options;  | 
2 |  | -using System;  | 
3 | 2 | using System.ComponentModel.Composition;  | 
4 |  | -using System.Linq;  | 
 | 3 | +using System.IO;  | 
5 | 4 | using System.Threading.Tasks;  | 
6 |  | -using System.Xml.Linq;  | 
7 |  | -using System.Xml.XPath;  | 
8 | 5 | 
 
  | 
9 | 6 | namespace FineCodeCoverage.Engine.Model  | 
10 | 7 | {  | 
11 | 8 |     [Export(typeof(ICoverageProjectSettingsManager))]  | 
12 | 9 |     internal class CoverageProjectSettingsManager : ICoverageProjectSettingsManager  | 
13 | 10 |     {  | 
14 | 11 |         private readonly IAppOptionsProvider appOptionsProvider;  | 
15 |  | -        private readonly ILogger logger;  | 
16 |  | -        private readonly IVsBuildFCCSettingsProvider vsBuildFCCSettingsProvider;  | 
 | 12 | +        private readonly ICoverageProjectSettingsProvider coverageProjectSettingsProvider;  | 
 | 13 | +        private readonly IFCCSettingsFilesProvider fccSettingsFilesProvider;  | 
 | 14 | +        private readonly ISettingsMerger settingsMerger;  | 
17 | 15 | 
 
  | 
18 | 16 |         [ImportingConstructor]  | 
19 | 17 |         public CoverageProjectSettingsManager(  | 
20 | 18 |             IAppOptionsProvider appOptionsProvider,  | 
21 |  | -            ILogger logger,  | 
22 |  | -            IVsBuildFCCSettingsProvider vsBuildFCCSettingsProvider  | 
 | 19 | +            ICoverageProjectSettingsProvider coverageProjectSettingsProvider,  | 
 | 20 | +            IFCCSettingsFilesProvider fccSettingsFilesProvider,  | 
 | 21 | +            ISettingsMerger settingsMerger  | 
23 | 22 |         )  | 
24 | 23 |         {  | 
25 | 24 |             this.appOptionsProvider = appOptionsProvider;  | 
26 |  | -            this.logger = logger;  | 
27 |  | -            this.vsBuildFCCSettingsProvider = vsBuildFCCSettingsProvider;  | 
28 |  | -        }  | 
29 |  | - | 
30 |  | -        private bool TypeMatch(Type type, params Type[] otherTypes)  | 
31 |  | -        {  | 
32 |  | -            return (otherTypes ?? new Type[0]).Any(ot => type == ot);  | 
33 |  | -        }  | 
34 |  | - | 
35 |  | -        private async Task<XElement> GetSettingsElementAsync(ICoverageProject coverageProject)  | 
36 |  | -        {  | 
37 |  | -            var settingsElement = SettingsElementFromFCCLabelledPropertyGroup(coverageProject);  | 
38 |  | -            if (settingsElement == null)  | 
39 |  | -            {  | 
40 |  | -                settingsElement = await vsBuildFCCSettingsProvider.GetSettingsAsync(coverageProject.Id);  | 
41 |  | -            }  | 
42 |  | -            return settingsElement;  | 
43 |  | -        }  | 
44 |  | - | 
45 |  | -        private XElement SettingsElementFromFCCLabelledPropertyGroup(ICoverageProject coverageProject)  | 
46 |  | -        {  | 
47 |  | -            /*  | 
48 |  | -            <PropertyGroup Label="FineCodeCoverage">  | 
49 |  | -                ...  | 
50 |  | -            </PropertyGroup>  | 
51 |  | -            */  | 
52 |  | -            return coverageProject.ProjectFileXElement.XPathSelectElement($"/PropertyGroup[@Label='{Vsix.Code}']");  | 
 | 25 | +            this.coverageProjectSettingsProvider = coverageProjectSettingsProvider;  | 
 | 26 | +            this.fccSettingsFilesProvider = fccSettingsFilesProvider;  | 
 | 27 | +            this.settingsMerger = settingsMerger;  | 
53 | 28 |         }  | 
54 | 29 | 
 
  | 
55 | 30 |         public async Task<IAppOptions> GetSettingsAsync(ICoverageProject coverageProject)  | 
56 | 31 |         {  | 
57 |  | -            // get global settings  | 
58 |  | - | 
59 |  | -            var settings = appOptionsProvider.Get();  | 
60 |  | - | 
61 |  | -            var settingsElement = await GetSettingsElementAsync(coverageProject);  | 
62 |  | - | 
63 |  | -            if (settingsElement != null)  | 
64 |  | -            {  | 
65 |  | -                foreach (var property in settings.GetType().GetProperties())  | 
66 |  | -                {  | 
67 |  | -                    try  | 
68 |  | -                    {  | 
69 |  | -                        var xproperty = settingsElement.Descendants().FirstOrDefault(x => x.Name.LocalName.Equals(property.Name, StringComparison.OrdinalIgnoreCase));  | 
70 |  | - | 
71 |  | -                        if (xproperty == null)  | 
72 |  | -                        {  | 
73 |  | -                            continue;  | 
74 |  | -                        }  | 
75 |  | - | 
76 |  | -                        var strValue = xproperty.Value;  | 
77 |  | - | 
78 |  | -                        if (string.IsNullOrWhiteSpace(strValue))  | 
79 |  | -                        {  | 
80 |  | -                            continue;  | 
81 |  | -                        }  | 
82 |  | - | 
83 |  | -                        var strValueArr = strValue.Split('\n', '\r').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).ToArray();  | 
84 |  | - | 
85 |  | -                        if (!strValue.Any())  | 
86 |  | -                        {  | 
87 |  | -                            continue;  | 
88 |  | -                        }  | 
89 |  | - | 
90 |  | -                        if (TypeMatch(property.PropertyType, typeof(string)))  | 
91 |  | -                        {  | 
92 |  | -                            property.SetValue(settings, strValueArr.FirstOrDefault());  | 
93 |  | -                        }  | 
94 |  | -                        else if (TypeMatch(property.PropertyType, typeof(string[])))  | 
95 |  | -                        {  | 
96 |  | -                            property.SetValue(settings, strValueArr);  | 
97 |  | -                        }  | 
98 |  | - | 
99 |  | -                        else if (TypeMatch(property.PropertyType, typeof(bool), typeof(bool?)))  | 
100 |  | -                        {  | 
101 |  | -                            if (bool.TryParse(strValueArr.FirstOrDefault(), out bool value))  | 
102 |  | -                            {  | 
103 |  | -                                property.SetValue(settings, value);  | 
104 |  | -                            }  | 
105 |  | -                        }  | 
106 |  | -                        else if (TypeMatch(property.PropertyType, typeof(bool[]), typeof(bool?[])))  | 
107 |  | -                        {  | 
108 |  | -                            var arr = strValueArr.Where(x => bool.TryParse(x, out var _)).Select(x => bool.Parse(x));  | 
109 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
110 |  | -                        }  | 
111 |  | - | 
112 |  | -                        else if (TypeMatch(property.PropertyType, typeof(int), typeof(int?)))  | 
113 |  | -                        {  | 
114 |  | -                            if (int.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
115 |  | -                            {  | 
116 |  | -                                property.SetValue(settings, value);  | 
117 |  | -                            }  | 
118 |  | -                        }  | 
119 |  | -                        else if (TypeMatch(property.PropertyType, typeof(int[]), typeof(int?[])))  | 
120 |  | -                        {  | 
121 |  | -                            var arr = strValueArr.Where(x => int.TryParse(x, out var _)).Select(x => int.Parse(x));  | 
122 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
123 |  | -                        }  | 
124 |  | - | 
125 |  | -                        else if (TypeMatch(property.PropertyType, typeof(short), typeof(short?)))  | 
126 |  | -                        {  | 
127 |  | -                            if (short.TryParse(strValueArr.FirstOrDefault(), out var vaue))  | 
128 |  | -                            {  | 
129 |  | -                                property.SetValue(settings, vaue);  | 
130 |  | -                            }  | 
131 |  | -                        }  | 
132 |  | -                        else if (TypeMatch(property.PropertyType, typeof(short[]), typeof(short?[])))  | 
133 |  | -                        {  | 
134 |  | -                            var arr = strValueArr.Where(x => short.TryParse(x, out var _)).Select(x => short.Parse(x));  | 
135 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
136 |  | -                        }  | 
137 |  | - | 
138 |  | -                        else if (TypeMatch(property.PropertyType, typeof(long), typeof(long?)))  | 
139 |  | -                        {  | 
140 |  | -                            if (long.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
141 |  | -                            {  | 
142 |  | -                                property.SetValue(settings, value);  | 
143 |  | -                            }  | 
144 |  | -                        }  | 
145 |  | -                        else if (TypeMatch(property.PropertyType, typeof(long[]), typeof(long?[])))  | 
146 |  | -                        {  | 
147 |  | -                            var arr = strValueArr.Where(x => long.TryParse(x, out var _)).Select(x => long.Parse(x));  | 
148 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
149 |  | -                        }  | 
150 |  | - | 
151 |  | -                        else if (TypeMatch(property.PropertyType, typeof(decimal), typeof(decimal?)))  | 
152 |  | -                        {  | 
153 |  | -                            if (decimal.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
154 |  | -                            {  | 
155 |  | -                                property.SetValue(settings, value);  | 
156 |  | -                            }  | 
157 |  | -                        }  | 
158 |  | -                        else if (TypeMatch(property.PropertyType, typeof(decimal[]), typeof(decimal?[])))  | 
159 |  | -                        {  | 
160 |  | -                            var arr = strValueArr.Where(x => decimal.TryParse(x, out var _)).Select(x => decimal.Parse(x));  | 
161 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
162 |  | -                        }  | 
163 |  | - | 
164 |  | -                        else if (TypeMatch(property.PropertyType, typeof(double), typeof(double?)))  | 
165 |  | -                        {  | 
166 |  | -                            if (double.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
167 |  | -                            {  | 
168 |  | -                                property.SetValue(settings, value);  | 
169 |  | -                            }  | 
170 |  | -                        }  | 
171 |  | -                        else if (TypeMatch(property.PropertyType, typeof(double[]), typeof(double?[])))  | 
172 |  | -                        {  | 
173 |  | -                            var arr = strValueArr.Where(x => double.TryParse(x, out var _)).Select(x => double.Parse(x));  | 
174 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
175 |  | -                        }  | 
176 |  | - | 
177 |  | -                        else if (TypeMatch(property.PropertyType, typeof(float), typeof(float?)))  | 
178 |  | -                        {  | 
179 |  | -                            if (float.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
180 |  | -                            {  | 
181 |  | -                                property.SetValue(settings, value);  | 
182 |  | -                            }  | 
183 |  | -                        }  | 
184 |  | -                        else if (TypeMatch(property.PropertyType, typeof(float[]), typeof(float?[])))  | 
185 |  | -                        {  | 
186 |  | -                            var arr = strValueArr.Where(x => float.TryParse(x, out var _)).Select(x => float.Parse(x));  | 
187 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
188 |  | -                        }  | 
189 |  | - | 
190 |  | -                        else if (TypeMatch(property.PropertyType, typeof(char), typeof(char?)))  | 
191 |  | -                        {  | 
192 |  | -                            if (char.TryParse(strValueArr.FirstOrDefault(), out var value))  | 
193 |  | -                            {  | 
194 |  | -                                property.SetValue(settings, value);  | 
195 |  | -                            }  | 
196 |  | -                        }  | 
197 |  | -                        else if (TypeMatch(property.PropertyType, typeof(char[]), typeof(char?[])))  | 
198 |  | -                        {  | 
199 |  | -                            var arr = strValueArr.Where(x => char.TryParse(x, out var _)).Select(x => char.Parse(x));  | 
200 |  | -                            if (arr.Any()) property.SetValue(settings, arr);  | 
201 |  | -                        }  | 
202 |  | - | 
203 |  | -                        else  | 
204 |  | -                        {  | 
205 |  | -                            throw new Exception($"Cannot handle '{property.PropertyType.Name}' yet");  | 
206 |  | -                        }  | 
207 |  | -                    }  | 
208 |  | -                    catch (Exception exception)  | 
209 |  | -                    {  | 
210 |  | -                        logger.Log($"Failed to override '{property.Name}' setting", exception);  | 
211 |  | -                    }  | 
212 |  | -                }  | 
213 |  | -            }  | 
214 |  | - | 
215 |  | -            return settings;  | 
 | 32 | +            var projectDirectory = Path.GetDirectoryName(coverageProject.ProjectFile);  | 
 | 33 | +            var settingsFilesElements = fccSettingsFilesProvider.Provide(projectDirectory);  | 
 | 34 | +            var projectSettingsElement = await coverageProjectSettingsProvider.ProvideAsync(coverageProject);  | 
 | 35 | +            return settingsMerger.Merge(appOptionsProvider.Get(), settingsFilesElements, projectSettingsElement);  | 
216 | 36 |         }  | 
217 | 37 |     }  | 
218 | 38 | 
 
  | 
 | 
0 commit comments