From 99ea4fed8aa07b87d51ea1dd54186cf24d4fedd9 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 14 May 2015 22:23:12 -0700 Subject: [PATCH] #176 Add Clone() to MediaTypeHeaderValue and NameValueHeaderValue. --- .../MediaTypeHeaderValue.cs | 21 ++++++++++++++ .../NameValueHeaderValue.cs | 13 +++++++++ .../MediaTypeHeaderValueTest.cs | 28 +++++++++++++++++++ .../NameValueHeaderValueTest.cs | 26 +++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs b/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs index 4113f44598..173bf7c404 100644 --- a/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs +++ b/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs @@ -248,6 +248,27 @@ namespace Microsoft.Net.Http.Headers return true; } + /// + /// Performs a deep copy of this object and all of it's NameValueHeaderValue sub components, + /// while avoiding the cost of revalidating the components. + /// + /// A deep copy. + public MediaTypeHeaderValue Clone() + { + var other = new MediaTypeHeaderValue(); + other._mediaType = _mediaType; + + if (_parameters != null) + { + other._parameters = new ObjectCollection(); + foreach (var pair in _parameters) + { + other._parameters.Add(pair.Clone()); + } + } + return other; + } + public override string ToString() { return _mediaType + NameValueHeaderValue.ToString(_parameters, ';', true); diff --git a/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs b/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs index 668a4ccef4..08a08f96ef 100644 --- a/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs +++ b/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs @@ -54,6 +54,19 @@ namespace Microsoft.Net.Http.Headers } } + /// + /// Provides a copy of this object without the cost of re-validating the values. + /// + /// A copy. + public NameValueHeaderValue Clone() + { + return new NameValueHeaderValue() + { + _name = _name, + _value = _value + }; + } + public override int GetHashCode() { Contract.Assert(_name != null); diff --git a/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs b/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs index 5c73d9b607..92ec8f9726 100644 --- a/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs +++ b/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs @@ -64,6 +64,34 @@ namespace Microsoft.Net.Http.Headers Assert.Throws(() => mediaType.Parameters.Add(null)); } + [Fact] + public void Clone_SimpleMediaType_Copied() + { + var mediaType0 = new MediaTypeHeaderValue("text/plain"); + var mediaType1 = mediaType0.Clone(); + Assert.NotSame(mediaType0, mediaType1); + Assert.Same(mediaType0.MediaType, mediaType1.MediaType); + Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters); + Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count); + } + + [Fact] + public void Clone_WithParameters_Copied() + { + var mediaType0 = new MediaTypeHeaderValue("text/plain"); + mediaType0.Parameters.Add(new NameValueHeaderValue("name", "value")); + var mediaType1 = mediaType0.Clone(); + Assert.NotSame(mediaType0, mediaType1); + Assert.Same(mediaType0.MediaType, mediaType1.MediaType); + Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters); + Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count); + var pair0 = mediaType0.Parameters.First(); + var pair1 = mediaType1.Parameters.First(); + Assert.NotSame(pair0, pair1); + Assert.Same(pair0.Name, pair1.Name); + Assert.Same(pair0.Value, pair1.Value); + } + [Fact] public void MediaType_SetAndGetMediaType_MatchExpectations() { diff --git a/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs b/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs index 3d342dea9b..a1e1a935f9 100644 --- a/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs +++ b/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs @@ -59,6 +59,32 @@ namespace Microsoft.Net.Http.Headers CheckValue("\"quoted string with quoted \\\" quote-pair\""); } + [Fact] + public void Clone_NameOnly_SuccesfullyCopied() + { + var pair0 = new NameValueHeaderValue("name"); + var pair1 = pair0.Clone(); + Assert.NotSame(pair0, pair1); + Assert.Same(pair0.Name, pair1.Name); + Assert.Null(pair0.Value); + Assert.Null(pair1.Value); + } + + [Fact] + public void Clone_NameAndValue_SuccesfullyCopied() + { + var pair0 = new NameValueHeaderValue("name", "value"); + var pair1 = pair0.Clone(); + Assert.NotSame(pair0, pair1); + Assert.Same(pair0.Name, pair1.Name); + Assert.Same(pair0.Value, pair1.Value); + + // Change one value and verify the other is unchanged. + pair1.Value = "othervalue"; + Assert.Equal("value", pair0.Value); + Assert.Equal("othervalue", pair1.Value); + } + [Fact] public void Value_CallSetterWithInvalidValues_Throw() {