Skip to content

Commit 84d5289

Browse files
committed
Improve System.Security.Cryptography.Xml code coverage
Add tests to fill some coverage gaps
1 parent c507305 commit 84d5289

17 files changed

+3013
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.IO;
5+
using System.Text;
6+
using System.Xml;
7+
using Xunit;
8+
9+
namespace System.Security.Cryptography.Xml.Tests
10+
{
11+
public class CanonicalXmlEntityReferenceTest
12+
{
13+
[Fact]
14+
public void EntityReferenceInCanonicalization()
15+
{
16+
// This test exercises CanonicalXmlEntityReference by using a transform
17+
// that internally creates a CanonicalXmlDocument and loads XML into it.
18+
// When an XmlNodeReader reads from a document containing entity references,
19+
// the target document's CreateEntityReference method is called.
20+
21+
string xml = @"<!DOCTYPE doc [
22+
<!ENTITY test ""TestValue"">
23+
]>
24+
<root>&test;</root>";
25+
26+
XmlDocument doc = new XmlDocument();
27+
doc.PreserveWhitespace = true;
28+
doc.LoadXml(xml);
29+
30+
// Use C14N transform which internally uses CanonicalXmlDocument
31+
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
32+
transform.LoadInput(doc);
33+
34+
Stream output = (Stream)transform.GetOutput();
35+
string result = new StreamReader(output, Encoding.UTF8).ReadToEnd();
36+
37+
// Entity should be expanded in canonical form
38+
Assert.Equal("<root>TestValue</root>", result);
39+
}
40+
41+
[Fact]
42+
public void EntityReferenceWithXmlNodeList()
43+
{
44+
// Test with XmlNodeList input which triggers different code path in CanonicalXml
45+
// When using XmlNodeList, nodes not in the list are not included, which may affect
46+
// entity reference expansion in the canonical output
47+
string xml = @"<!DOCTYPE doc [
48+
<!ENTITY test ""Hello"">
49+
]>
50+
<root><child>&test;</child></root>";
51+
52+
XmlDocument doc = new XmlDocument();
53+
doc.PreserveWhitespace = true;
54+
doc.LoadXml(xml);
55+
56+
XmlNodeList nodeList = doc.SelectNodes("//child")!;
57+
58+
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
59+
transform.LoadInput(nodeList);
60+
61+
Stream output = (Stream)transform.GetOutput();
62+
string result = new StreamReader(output, Encoding.UTF8).ReadToEnd();
63+
64+
// Only the child element should be in the result (entity not expanded since only child element is in XPath)
65+
Assert.Equal("<child></child>", result);
66+
}
67+
68+
[Fact]
69+
public void EntityReferenceWithCommentsIncluded()
70+
{
71+
// Test with includeComments = true
72+
string xml = @"<!DOCTYPE doc [
73+
<!ENTITY ent ""EntityContent"">
74+
]>
75+
<root><!--comment-->&ent;</root>";
76+
77+
XmlDocument doc = new XmlDocument();
78+
doc.PreserveWhitespace = true;
79+
doc.LoadXml(xml);
80+
81+
XmlDsigC14NWithCommentsTransform transform = new XmlDsigC14NWithCommentsTransform();
82+
transform.LoadInput(doc);
83+
84+
Stream output = (Stream)transform.GetOutput();
85+
string result = new StreamReader(output, Encoding.UTF8).ReadToEnd();
86+
87+
// Both comment and expanded entity should be in output
88+
Assert.Contains("<!--comment-->", result);
89+
Assert.Contains("EntityContent", result);
90+
}
91+
92+
[Fact]
93+
public void EntityReferenceInExclusiveCanonicalization()
94+
{
95+
// Test with Exclusive C14N transform
96+
string xml = @"<!DOCTYPE doc [
97+
<!ENTITY test ""ExclusiveTest"">
98+
]>
99+
<root xmlns=""http://example.com"">&test;</root>";
100+
101+
XmlDocument doc = new XmlDocument();
102+
doc.PreserveWhitespace = true;
103+
doc.LoadXml(xml);
104+
105+
XmlDsigExcC14NTransform transform = new XmlDsigExcC14NTransform();
106+
transform.LoadInput(doc);
107+
108+
Stream output = (Stream)transform.GetOutput();
109+
string result = new StreamReader(output, Encoding.UTF8).ReadToEnd();
110+
111+
// Entity should be expanded in canonical form
112+
Assert.Contains("ExclusiveTest", result);
113+
Assert.Contains("http://example.com", result);
114+
}
115+
116+
[Fact]
117+
public void EntityReferenceWithHash()
118+
{
119+
// Test the WriteHash code path by using GetDigestedOutput
120+
string xml = @"<!DOCTYPE doc [
121+
<!ENTITY test ""HashTest"">
122+
]>
123+
<root>&test;</root>";
124+
125+
XmlDocument doc = new XmlDocument();
126+
doc.PreserveWhitespace = true;
127+
doc.LoadXml(xml);
128+
129+
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
130+
transform.LoadInput(doc);
131+
132+
using (SHA256 hash = SHA256.Create())
133+
{
134+
byte[] digest = transform.GetDigestedOutput(hash);
135+
136+
// Should produce a valid hash
137+
Assert.NotNull(digest);
138+
Assert.Equal(32, digest.Length); // SHA256 produces 32 bytes
139+
}
140+
}
141+
142+
[Fact]
143+
public void MultipleEntityReferences()
144+
{
145+
// Test with multiple entity references
146+
string xml = @"<!DOCTYPE doc [
147+
<!ENTITY ent1 ""First"">
148+
<!ENTITY ent2 ""Second"">
149+
]>
150+
<root>&ent1; and &ent2;</root>";
151+
152+
XmlDocument doc = new XmlDocument();
153+
doc.PreserveWhitespace = true;
154+
doc.LoadXml(xml);
155+
156+
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
157+
transform.LoadInput(doc);
158+
159+
Stream output = (Stream)transform.GetOutput();
160+
string result = new StreamReader(output, Encoding.UTF8).ReadToEnd();
161+
162+
// Both entities should be expanded
163+
Assert.Contains("First", result);
164+
Assert.Contains("Second", result);
165+
Assert.Contains("and", result);
166+
}
167+
}
168+
}

src/libraries/System.Security.Cryptography.Xml/tests/DataObjectTests.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,5 +161,157 @@ private static XmlElement CreateTestElement(string name, string idValue, string
161161

162162
return element;
163163
}
164+
165+
[Fact]
166+
public void LoadXml_InvalidElement()
167+
{
168+
XmlDocument doc = new XmlDocument();
169+
doc.LoadXml("<WrongElement />");
170+
171+
DataObject dataObject = new DataObject();
172+
dataObject.Id = "test-id";
173+
dataObject.Encoding = "UTF-8";
174+
// LoadXml replaces the properties, so pre-set values are overwritten
175+
dataObject.LoadXml(doc.DocumentElement);
176+
Assert.NotNull(dataObject.Data);
177+
// LoadXml reads from the XML, not the pre-set values
178+
Assert.Null(dataObject.Id);
179+
Assert.Null(dataObject.Encoding);
180+
}
181+
182+
[Fact]
183+
public void GetXml_WithData()
184+
{
185+
DataObject dataObject = new DataObject();
186+
XmlDocument doc = new XmlDocument();
187+
XmlElement elem = doc.CreateElement("TestData");
188+
elem.InnerText = "test content";
189+
dataObject.Data = new XmlNodeList[] { elem.ChildNodes }[0];
190+
191+
XmlElement xml = dataObject.GetXml();
192+
Assert.NotNull(xml);
193+
Assert.Equal("Object", xml.LocalName);
194+
// The InnerText "test content" is a text node, verify it appears in the output
195+
Assert.Contains("test content", xml.InnerXml);
196+
}
197+
198+
[Fact]
199+
public void Properties_SetAndGet()
200+
{
201+
DataObject dataObject = new DataObject();
202+
203+
dataObject.Id = "obj-1";
204+
Assert.Equal("obj-1", dataObject.Id);
205+
206+
dataObject.MimeType = "text/xml";
207+
Assert.Equal("text/xml", dataObject.MimeType);
208+
209+
dataObject.Encoding = "UTF-8";
210+
Assert.Equal("UTF-8", dataObject.Encoding);
211+
212+
Assert.NotNull(dataObject.Data);
213+
}
214+
215+
[Fact]
216+
public void LoadXml_WithData()
217+
{
218+
string xml = @"<Object Id=""obj1"" xmlns=""http://www.w3.org/2000/09/xmldsig#"">
219+
<test>data</test>
220+
</Object>";
221+
XmlDocument doc = new XmlDocument();
222+
doc.LoadXml(xml);
223+
224+
DataObject dataObject = new DataObject();
225+
dataObject.LoadXml(doc.DocumentElement);
226+
Assert.Equal("obj1", dataObject.Id);
227+
Assert.Equal(1, dataObject.Data.Count);
228+
}
229+
230+
[Fact]
231+
public void LoadXml_NoId()
232+
{
233+
string xml = @"<Object xmlns=""http://www.w3.org/2000/09/xmldsig#"">
234+
<test>data</test>
235+
</Object>";
236+
XmlDocument doc = new XmlDocument();
237+
doc.LoadXml(xml);
238+
239+
DataObject dataObject = new DataObject();
240+
dataObject.LoadXml(doc.DocumentElement);
241+
Assert.Null(dataObject.Id);
242+
}
243+
244+
[Fact]
245+
public void LoadXml_NoMimeType()
246+
{
247+
string xml = @"<Object Id=""obj1"" xmlns=""http://www.w3.org/2000/09/xmldsig#"">
248+
<test>data</test>
249+
</Object>";
250+
XmlDocument doc = new XmlDocument();
251+
doc.LoadXml(xml);
252+
253+
DataObject dataObject = new DataObject();
254+
dataObject.LoadXml(doc.DocumentElement);
255+
Assert.Null(dataObject.MimeType);
256+
}
257+
258+
[Fact]
259+
public void LoadXml_NoEncoding()
260+
{
261+
string xml = @"<Object Id=""obj1"" xmlns=""http://www.w3.org/2000/09/xmldsig#"">
262+
<test>data</test>
263+
</Object>";
264+
XmlDocument doc = new XmlDocument();
265+
doc.LoadXml(xml);
266+
267+
DataObject dataObject = new DataObject();
268+
dataObject.LoadXml(doc.DocumentElement);
269+
Assert.Null(dataObject.Encoding);
270+
}
271+
272+
[Fact]
273+
public void GetXml_NoData()
274+
{
275+
DataObject dataObject = new DataObject();
276+
dataObject.Id = "obj1";
277+
278+
XmlElement xml = dataObject.GetXml();
279+
Assert.NotNull(xml);
280+
Assert.Equal(@"<Object Id=""obj1"" xmlns=""http://www.w3.org/2000/09/xmldsig#"" />", xml.OuterXml);
281+
}
282+
283+
[Fact]
284+
public void GetXml_EmptyStrings()
285+
{
286+
DataObject dataObject = new DataObject();
287+
dataObject.Id = "";
288+
dataObject.MimeType = "";
289+
dataObject.Encoding = "";
290+
291+
XmlElement xml = dataObject.GetXml();
292+
// Verify the full output XML - empty strings for MimeType and Encoding mean no attributes are added
293+
Assert.Equal(@"<Object xmlns=""http://www.w3.org/2000/09/xmldsig#"" />", xml.OuterXml);
294+
}
295+
296+
[Fact]
297+
public void Constructor_NullArguments()
298+
{
299+
XmlDocument doc = new XmlDocument();
300+
XmlElement elem = doc.CreateElement("test");
301+
302+
DataObject dataObject = new DataObject(null, null, null, elem);
303+
Assert.Null(dataObject.Id);
304+
Assert.Null(dataObject.MimeType);
305+
Assert.Null(dataObject.Encoding);
306+
Assert.NotNull(dataObject.Data);
307+
308+
// Verify GetXml output - should include the test element content
309+
XmlElement xml = dataObject.GetXml();
310+
Assert.NotNull(xml);
311+
Assert.Equal("Object", xml.LocalName);
312+
Assert.Equal(SignedXml.XmlDsigNamespaceUrl, xml.NamespaceURI);
313+
// The element should contain the child element
314+
Assert.Contains("<test", xml.InnerXml);
315+
}
164316
}
165317
}

src/libraries/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,72 @@ public void LoadXml()
2525
EncryptedKey ek = new EncryptedKey();
2626
ek.LoadXml(doc.DocumentElement);
2727
}
28+
29+
[Fact]
30+
public void Constructor_Empty()
31+
{
32+
DataReference dataRef = new DataReference();
33+
Assert.Equal(string.Empty, dataRef.Uri);
34+
}
35+
36+
[Fact]
37+
public void Constructor_WithUri()
38+
{
39+
string uri = "#data1";
40+
DataReference dataRef = new DataReference(uri);
41+
Assert.Equal(uri, dataRef.Uri);
42+
}
43+
44+
[Fact]
45+
public void Constructor_WithUriAndTransformChain()
46+
{
47+
string uri = "#data1";
48+
TransformChain tc = new TransformChain();
49+
tc.Add(new XmlDsigBase64Transform());
50+
51+
DataReference dataRef = new DataReference(uri, tc);
52+
Assert.Equal(uri, dataRef.Uri);
53+
Assert.NotNull(dataRef.TransformChain);
54+
Assert.Equal(1, dataRef.TransformChain.Count);
55+
}
56+
57+
[Fact]
58+
public void GetXml_SimpleDataReference()
59+
{
60+
DataReference dataRef = new DataReference("#encrypted-data-1");
61+
XmlElement xml = dataRef.GetXml();
62+
Assert.Equal(@"<DataReference URI=""#encrypted-data-1"" xmlns=""http://www.w3.org/2001/04/xmlenc#"" />", xml.OuterXml);
63+
}
64+
65+
[Fact]
66+
public void GetXml_WithTransforms()
67+
{
68+
DataReference dataRef = new DataReference("#data1");
69+
dataRef.TransformChain.Add(new XmlDsigC14NTransform());
70+
71+
XmlElement xml = dataRef.GetXml();
72+
Assert.Equal("DataReference", xml.LocalName);
73+
Assert.NotNull(xml.SelectSingleNode("//*[local-name()='Transforms']"));
74+
}
75+
76+
[Fact]
77+
public void LoadXml_SimpleDataReference()
78+
{
79+
string xml = @"<DataReference URI=""#encrypted-element"" xmlns=""http://www.w3.org/2001/04/xmlenc#"" />";
80+
XmlDocument doc = new XmlDocument();
81+
doc.LoadXml(xml);
82+
83+
DataReference dataRef = new DataReference();
84+
dataRef.LoadXml(doc.DocumentElement);
85+
Assert.Equal("#encrypted-element", dataRef.Uri);
86+
}
87+
88+
[Fact]
89+
public void ReferenceType_IsDataReference()
90+
{
91+
DataReference dataRef = new DataReference();
92+
XmlElement xml = dataRef.GetXml();
93+
Assert.Equal("DataReference", xml.LocalName);
94+
}
2895
}
2996
}

0 commit comments

Comments
 (0)