Skip to content

Commit 5a00670

Browse files
committed
.
1 parent 63e58c5 commit 5a00670

File tree

1 file changed

+181
-13
lines changed

1 file changed

+181
-13
lines changed

src/Verify/Verifier/InnerVerifier_Inner.cs

Lines changed: 181 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,58 @@ target.Extension is null ||
118118
return (results, cleanup);
119119
}
120120

121-
// Target contains an arbitrary object - resolve it
121+
// Target contains an arbitrary object - resolve it using full type matching
122122
var data = target.Data;
123123
if (data is null)
124124
{
125125
return (results, cleanup);
126126
}
127127

128-
// Handle Stream without extension
129-
if (data is Stream stream2)
128+
// Handle XContainer (XDocument, XElement)
129+
if (data is XContainer container)
130130
{
131-
results.Add(new ResolvedTarget("bin", stream2, target.Name));
131+
var xmlString = ConvertXmlToString(container);
132+
results.Add(new ResolvedTarget("xml", xmlString, target.Name));
132133
return (results, cleanup);
133134
}
134135

136+
// Handle XmlNode
137+
if (data is XmlNode node)
138+
{
139+
using var reader = new XmlNodeReader(node);
140+
reader.MoveToContent();
141+
var xdoc = XDocument.Load(reader);
142+
var xmlString = ConvertXmlToString(xdoc);
143+
results.Add(new ResolvedTarget("xml", xmlString, target.Name));
144+
return (results, cleanup);
145+
}
146+
147+
// Handle FileStream (get extension from filename)
148+
if (data is FileStream fileStream)
149+
{
150+
var extension = fileStream.Extension();
151+
return await ResolveStream(fileStream, extension, target.Name);
152+
}
153+
154+
// Handle Stream
155+
if (data is Stream stream2)
156+
{
157+
return await ResolveStream(stream2, "bin", target.Name);
158+
}
159+
160+
// Handle byte[]
161+
if (data is byte[] bytes)
162+
{
163+
var memStream = new MemoryStream(bytes);
164+
return await ResolveStream(memStream, "bin", target.Name);
165+
}
166+
167+
// Handle IEnumerable<Stream> - throw error as in Verify(object)
168+
if (data is IEnumerable<Stream>)
169+
{
170+
throw new("Use Verify(IEnumerable<T> targets, string extension)");
171+
}
172+
135173
// Handle StringBuilder
136174
if (data is StringBuilder sb2)
137175
{
@@ -146,6 +184,15 @@ target.Extension is null ||
146184
return (results, cleanup);
147185
}
148186

187+
// Try ToString converter (before typed converter, matching Verify(object) order)
188+
if (VerifierSettings.TryGetToString(data, out var toString))
189+
{
190+
var stringResult = toString(data, settings.Context);
191+
var extension = stringResult.Extension ?? "txt";
192+
results.Add(new ResolvedTarget(extension, stringResult.Value, target.Name));
193+
return (results, cleanup);
194+
}
195+
149196
// Try typed converter
150197
if (VerifierSettings.TryGetTypedConverter(data, settings, out var converter))
151198
{
@@ -174,22 +221,143 @@ target.Extension is null ||
174221
return (results, cleanup);
175222
}
176223

177-
// Try ToString converter
178-
if (VerifierSettings.TryGetToString(data, out var toString))
179-
{
180-
var stringResult = toString(data, settings.Context);
181-
var extension = stringResult.Extension ?? "txt";
182-
results.Add(new ResolvedTarget(extension, stringResult.Value, target.Name));
183-
return (results, cleanup);
184-
}
185-
186224
// Fall back to JSON serialization
187225
results.Add(new ResolvedTarget(
188226
settings.TxtOrJson,
189227
JsonFormatter.AsJson(settings, counter, data)));
190228
return (results, cleanup);
191229
}
192230

231+
async Task<(List<ResolvedTarget> targets, Func<Task> cleanup)> ResolveStream(Stream stream, string extension, string? name)
232+
{
233+
var cleanup = () => Task.CompletedTask;
234+
var results = new List<ResolvedTarget>();
235+
236+
stream.MoveToStart();
237+
238+
// Check for stream converter
239+
if (VerifierSettings.HasStreamConverter(extension))
240+
{
241+
var (info, converted, convCleanup) = await DoExtensionConversion(extension, stream, null, name);
242+
cleanup += convCleanup;
243+
244+
// Add info target if present
245+
if (info != null)
246+
{
247+
results.Add(new ResolvedTarget(
248+
settings.TxtOrJson,
249+
JsonFormatter.AsJson(settings, counter, info)));
250+
}
251+
252+
// Recursively resolve converted targets (they may contain objects)
253+
foreach (var convTarget in converted)
254+
{
255+
var (resolved, resolveCleanup) = await ResolveTarget(convTarget);
256+
cleanup += resolveCleanup;
257+
results.AddRange(resolved);
258+
}
259+
260+
return (results, cleanup);
261+
}
262+
263+
// No converter - convert stream directly to ResolvedTarget
264+
if (FileExtensions.IsTextExtension(extension))
265+
{
266+
results.Add(new ResolvedTarget(extension, await stream.ReadStringBuilderWithFixedLines(), name));
267+
}
268+
else
269+
{
270+
results.Add(new ResolvedTarget(extension, stream, name));
271+
}
272+
273+
return (results, cleanup);
274+
}
275+
276+
string ConvertXmlToString(XContainer target)
277+
{
278+
var serialization = settings.serialization;
279+
var elements = target
280+
.Descendants()
281+
.ToList();
282+
283+
foreach (var element in elements)
284+
{
285+
if (serialization.TryGetScrubOrIgnoreByName(element.Name.LocalName, out var scrubOrIgnore))
286+
{
287+
if (scrubOrIgnore == ScrubOrIgnore.Ignore)
288+
{
289+
element.Remove();
290+
}
291+
else
292+
{
293+
element.Value = "Scrubbed";
294+
}
295+
296+
continue;
297+
}
298+
299+
ScrubXmlAttributes(element, serialization);
300+
}
301+
302+
foreach (var node in target.DescendantNodes())
303+
{
304+
switch (node)
305+
{
306+
case XText text:
307+
text.Value = ConvertXmlValue(text.Value);
308+
continue;
309+
case XComment comment:
310+
comment.Value = ConvertXmlValue(comment.Value);
311+
continue;
312+
}
313+
}
314+
315+
return target.ToString();
316+
}
317+
318+
string ConvertXmlValue(string value)
319+
{
320+
var span = value.AsSpan();
321+
if (counter.TryConvert(span, out var result))
322+
{
323+
return result;
324+
}
325+
326+
return ApplyScrubbers.ApplyForPropertyValue(span, settings, counter).ToString();
327+
}
328+
329+
void ScrubXmlAttributes(XElement node, SerializationSettings serialization)
330+
{
331+
foreach (var attribute in node
332+
.Attributes()
333+
.ToList())
334+
{
335+
if (serialization.TryGetScrubOrIgnoreByName(attribute.Name.LocalName, out var scrubOrIgnore))
336+
{
337+
if (scrubOrIgnore == ScrubOrIgnore.Ignore)
338+
{
339+
attribute.Remove();
340+
}
341+
else
342+
{
343+
attribute.Value = "Scrubbed";
344+
}
345+
346+
continue;
347+
}
348+
349+
var span = attribute.Value.AsSpan();
350+
if (counter.TryConvert(span, out var result))
351+
{
352+
attribute.Value = result;
353+
}
354+
else
355+
{
356+
attribute.Value = ApplyScrubbers.ApplyForPropertyValue(span, settings, counter).ToString();
357+
}
358+
}
359+
}
360+
193361
bool TryGetRootTarget(object? root, bool ignoreNullRoot, [NotNullWhen(true)] out ResolvedTarget? target)
194362
{
195363
var appends = VerifierSettings.GetJsonAppenders(settings);

0 commit comments

Comments
 (0)