src/SSC/Internal/XPathLikePathParser.cs

実行済み 124 · 未実行 6 · 対象外 187
Coverage source: 043e27b9e5febd713c747d2558802e450fad8edd

実行済みCoberturaのhit数が1以上の行です。
未実行カバレッジ対象ですがhit数が0の行です。
対象外Coberturaに実行対象として記録されていない行です。
行状態HitsSource
1 対象外 namespace SSC.Internal;
2 対象外
3 対象外 internal enum XPathLikePathSelectorKind
4 対象外 {
5 対象外 Key,
6 対象外 Ordinal,
7 対象外 }
8 対象外
9 対象外 internal sealed class XPathLikePath
10 対象外 {
11 実行済み 164 public XPathLikePath(string? rootName, IReadOnlyList<XPathLikePathSegment> segments)
12 対象外 {
13 実行済み 164 RootName = rootName;
14 実行済み 164 Segments = segments;
15 実行済み 164 }
16 対象外
17 実行済み 3 public string? RootName { get; }
18 対象外
19 実行済み 363 public IReadOnlyList<XPathLikePathSegment> Segments { get; }
20 対象外 }
21 対象外
22 対象外 internal sealed class XPathLikePathSegment
23 対象外 {
24 実行済み 334 public XPathLikePathSegment(string memberName, XPathLikePathSelector? selector)
25 対象外 {
26 実行済み 334 MemberName = memberName;
27 実行済み 334 Selector = selector;
28 実行済み 334 }
29 対象外
30 実行済み 266 public string MemberName { get; }
31 対象外
32 実行済み 376 public XPathLikePathSelector? Selector { get; }
33 対象外 }
34 対象外
35 対象外 internal sealed class XPathLikePathSelector
36 対象外 {
37 実行済み 145 private XPathLikePathSelector(XPathLikePathSelectorKind kind, string? keyText, int? ordinal)
38 対象外 {
39 実行済み 145 Kind = kind;
40 実行済み 145 KeyText = keyText;
41 実行済み 145 Ordinal = ordinal;
42 実行済み 145 }
43 対象外
44 実行済み 120 public XPathLikePathSelectorKind Kind { get; }
45 対象外
46 実行済み 95 public string? KeyText { get; }
47 対象外
48 実行済み 8 public int? Ordinal { get; }
49 対象外
50 対象外 public static XPathLikePathSelector Key(string keyText)
51 対象外 {
52 実行済み 132 return new XPathLikePathSelector(XPathLikePathSelectorKind.Key, keyText, null);
53 対象外 }
54 対象外
55 対象外 public static XPathLikePathSelector FromOrdinal(int ordinal)
56 対象外 {
57 実行済み 13 return new XPathLikePathSelector(XPathLikePathSelectorKind.Ordinal, null, ordinal);
58 対象外 }
59 対象外 }
60 対象外
61 対象外 internal static class XPathLikePathParser
62 対象外 {
63 対象外 public static bool TryParse(string path, out XPathLikePath? parsedPath)
64 対象外 {
65 実行済み 81 return TryParse(path, rootName: null, allowsEmptyKeySelector: false, out parsedPath);
66 対象外 }
67 対象外
68 対象外 public static bool TryParse(string path, string? rootName, out XPathLikePath? parsedPath)
69 対象外 {
70 実行済み 40 return TryParse(path, rootName, allowsEmptyKeySelector: false, out parsedPath);
71 対象外 }
72 対象外
73 対象外 /// <summary>
74 対象外 /// 既存の <c>GetDiffEntries()</c> が空文字列の比較 key に対して生成する legacy 空 selector を、空 key selector として解析します。
75 対象外 /// </summary>
76 対象外 /// <param name="path">解析する既存差分 path。</param>
77 対象外 /// <param name="parsedPath">解析に成功した場合の構造化 path。</param>
78 対象外 /// <returns>解析に成功した場合は <see langword="true"/>、それ以外は <see langword="false"/>。</returns>
79 対象外 internal static bool TryParseLegacyEmptyKeySelectorPath(string path, out XPathLikePath? parsedPath)
80 対象外 {
81 実行済み 60 return TryParse(path, rootName: null, allowsEmptyKeySelector: true, out parsedPath);
82 対象外 }
83 対象外
84 対象外 private static bool TryParse(
85 対象外 string path,
86 対象外 string? rootName,
87 対象外 bool allowsEmptyKeySelector,
88 対象外 out XPathLikePath? parsedPath)
89 対象外 {
90 実行済み 181 parsedPath = null;
91 実行済み 181 if (string.IsNullOrEmpty(path))
92 対象外 {
93 実行済み 1 return false;
94 対象外 }
95 対象外
96 実行済み 180 if (!TrySplitSegments(path, out var rawSegments))
97 対象外 {
98 実行済み 7 return false;
99 対象外 }
100 対象外
101 実行済み 173 var parsedRootName = GetRootName(rawSegments, rootName);
102 実行済み 173 var segmentStartIndex = parsedRootName is null ? 0 : 1;
103 実行済み 173 var segments = new List<XPathLikePathSegment>(rawSegments.Count - segmentStartIndex);
104 実行済み 1014 for (var index = segmentStartIndex; index < rawSegments.Count; index++)
105 対象外 {
106 実行済み 343 if (!TryParseSegment(rawSegments[index], allowsEmptyKeySelector, out var segment))
107 対象外 {
108 実行済み 9 return false;
109 対象外 }
110 対象外
111 実行済み 334 segments.Add(segment);
112 対象外 }
113 対象外
114 実行済み 164 if (segments.Count == 0)
115 対象外 {
116 未実行 0 return false;
117 対象外 }
118 対象外
119 実行済み 164 parsedPath = new XPathLikePath(parsedRootName, segments);
120 実行済み 164 return true;
121 対象外 }
122 対象外
123 対象外 private static string? GetRootName(IReadOnlyList<string> rawSegments, string? rootName)
124 対象外 {
125 実行済み 173 if (rootName is null
126 実行済み 173 || rawSegments.Count <= 1
127 実行済み 173 || rawSegments[0].Contains('[', StringComparison.Ordinal)
128 実行済み 173 || !string.Equals(rawSegments[0], rootName, StringComparison.Ordinal))
129 対象外 {
130 実行済み 166 return null;
131 対象外 }
132 対象外
133 実行済み 7 return rootName;
134 対象外 }
135 対象外
136 対象外 private static bool TrySplitSegments(string path, out List<string> segments)
137 対象外 {
138 実行済み 180 segments = [];
139 実行済み 180 var segmentStart = 0;
140 実行済み 180 var inSelector = false;
141 実行済み 180 var escaping = false;
142 実行済み 180 var selectorClosedInSegment = false;
143 対象外
144 実行済み 6092 for (var index = 0; index < path.Length; index++)
145 対象外 {
146 実行済み 2870 var current = path[index];
147 実行済み 2870 if (inSelector)
148 対象外 {
149 実行済み 600 if (escaping)
150 対象外 {
151 実行済み 22 escaping = false;
152 実行済み 22 continue;
153 対象外 }
154 対象外
155 実行済み 578 if (current == '\\')
156 対象外 {
157 実行済み 22 escaping = true;
158 実行済み 22 continue;
159 対象外 }
160 対象外
161 実行済み 556 if (current == ']')
162 対象外 {
163 実行済み 157 inSelector = false;
164 実行済み 157 selectorClosedInSegment = true;
165 対象外 }
166 対象外
167 実行済み 157 continue;
168 対象外 }
169 対象外
170 実行済み 2270 if (current == '[')
171 対象外 {
172 実行済み 161 if (selectorClosedInSegment)
173 対象外 {
174 実行済み 2 return false;
175 対象外 }
176 対象外
177 実行済み 159 inSelector = true;
178 実行済み 159 continue;
179 対象外 }
180 対象外
181 実行済み 2109 if (current == ']')
182 対象外 {
183 実行済み 1 return false;
184 対象外 }
185 対象外
186 実行済み 2108 if (current != '.')
187 対象外 {
188 対象外 continue;
189 対象外 }
190 対象外
191 実行済み 180 if (index == segmentStart)
192 対象外 {
193 実行済み 1 return false;
194 対象外 }
195 対象外
196 実行済み 179 segments.Add(path[segmentStart..index]);
197 実行済み 179 segmentStart = index + 1;
198 実行済み 179 selectorClosedInSegment = false;
199 対象外 }
200 対象外
201 実行済み 176 if (inSelector || escaping || segmentStart == path.Length)
202 対象外 {
203 実行済み 3 return false;
204 対象外 }
205 対象外
206 実行済み 173 segments.Add(path[segmentStart..]);
207 実行済み 173 return true;
208 対象外 }
209 対象外
210 対象外 private static bool TryParseSegment(
211 対象外 string rawSegment,
212 対象外 bool allowsEmptyKeySelector,
213 対象外 out XPathLikePathSegment segment)
214 対象外 {
215 実行済み 343 segment = null!;
216 実行済み 343 if (string.IsNullOrEmpty(rawSegment))
217 対象外 {
218 未実行 0 return false;
219 対象外 }
220 対象外
221 実行済み 343 var selectorStart = rawSegment.IndexOf('[', StringComparison.Ordinal);
222 実行済み 343 if (selectorStart < 0)
223 対象外 {
224 実行済み 189 segment = new XPathLikePathSegment(rawSegment, null);
225 実行済み 189 return true;
226 対象外 }
227 対象外
228 実行済み 154 if (selectorStart == 0 || !rawSegment.EndsWith(']'))
229 対象外 {
230 未実行 0 return false;
231 対象外 }
232 対象外
233 実行済み 154 var memberName = rawSegment[..selectorStart];
234 実行済み 154 var selectorText = rawSegment[(selectorStart + 1)..^1];
235 実行済み 154 if (memberName.Length == 0 || (selectorText.Length == 0 && !allowsEmptyKeySelector))
236 対象外 {
237 実行済み 5 return false;
238 対象外 }
239 対象外
240 実行済み 149 if (!TryParseSelector(selectorText, allowsEmptyKeySelector, out var selector))
241 対象外 {
242 実行済み 4 return false;
243 対象外 }
244 対象外
245 実行済み 145 segment = new XPathLikePathSegment(memberName, selector);
246 実行済み 145 return true;
247 対象外 }
248 対象外
249 対象外 private static bool TryParseSelector(
250 対象外 string selectorText,
251 対象外 bool allowsEmptyKeySelector,
252 対象外 out XPathLikePathSelector selector)
253 対象外 {
254 実行済み 149 selector = null!;
255 実行済み 149 if (selectorText.Length == 0 && allowsEmptyKeySelector)
256 対象外 {
257 実行済み 2 selector = XPathLikePathSelector.Key(string.Empty);
258 実行済み 2 return true;
259 対象外 }
260 対象外
261 実行済み 147 if (selectorText[0] == '#')
262 対象外 {
263 実行済み 15 if (selectorText.Length == 1 || !selectorText[1..].All(char.IsDigit))
264 対象外 {
265 実行済み 2 return false;
266 対象外 }
267 対象外
268 実行済み 13 if (!int.TryParse(selectorText[1..], out var ordinal))
269 対象外 {
270 未実行 0 return false;
271 対象外 }
272 対象外
273 実行済み 13 selector = XPathLikePathSelector.FromOrdinal(ordinal);
274 実行済み 13 return true;
275 対象外 }
276 対象外
277 実行済み 132 if (!TryUnescapeKey(selectorText, out var keyText) || keyText.Length == 0)
278 対象外 {
279 実行済み 2 return false;
280 対象外 }
281 対象外
282 実行済み 130 selector = XPathLikePathSelector.Key(keyText);
283 実行済み 130 return true;
284 対象外 }
285 対象外
286 対象外 private static bool TryUnescapeKey(string selectorText, out string keyText)
287 対象外 {
288 実行済み 132 var builder = new System.Text.StringBuilder(selectorText.Length);
289 実行済み 1032 for (var index = 0; index < selectorText.Length; index++)
290 対象外 {
291 実行済み 386 var current = selectorText[index];
292 実行済み 386 if (current != '\\')
293 対象外 {
294 実行済み 364 builder.Append(current);
295 実行済み 364 continue;
296 対象外 }
297 対象外
298 実行済み 22 if (index + 1 >= selectorText.Length)
299 対象外 {
300 未実行 0 keyText = string.Empty;
301 未実行 0 return false;
302 対象外 }
303 対象外
304 実行済み 22 var escaped = selectorText[++index];
305 実行済み 22 if (escaped is not (']' or '\\' or '#'))
306 対象外 {
307 実行済み 2 keyText = string.Empty;
308 実行済み 2 return false;
309 対象外 }
310 対象外
311 実行済み 20 builder.Append(escaped);
312 対象外 }
313 対象外
314 実行済み 130 keyText = builder.ToString();
315 実行済み 130 return true;
316 対象外 }
317 対象外 }