diff --git a/Build/Newtonsoft.Json.nuspec b/Build/Newtonsoft.Json.nuspec index 27eedf05..0b1eadb9 100644 --- a/Build/Newtonsoft.Json.nuspec +++ b/Build/Newtonsoft.Json.nuspec @@ -1,15 +1,47 @@  - - Newtonsoft.Json - - Json.NET - Json.NET is a popular high-performance JSON framework for .NET - James Newton-King - en-US - http://www.newtonsoft.com/json - http://www.newtonsoft.com/content/images/nugeticon.png - https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md - json - + + Newtonsoft.Json + + Json.NET + Json.NET is a popular high-performance JSON framework for .NET + James Newton-King + en-US + http://www.newtonsoft.com/json + http://www.newtonsoft.com/content/images/nugeticon.png + https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md + json + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index 7e6e6e86..da167a49 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,8 +1,8 @@ properties { - $zipFileName = "Json80r3.zip" + $zipFileName = "Json80r4.zip" $majorVersion = "8.0" - $majorWithReleaseVersion = "8.0.3" - $nugetPrelease = $null + $majorWithReleaseVersion = "8.0.4" + $nugetPrerelease = "beta1" $version = GetVersion $majorWithReleaseVersion $packageId = "Newtonsoft.Json" $signAssemblies = $false @@ -11,7 +11,7 @@ $buildNuGet = $true $treatWarningsAsErrors = $false $workingName = if ($workingName) {$workingName} else {"Working"} - $dnvmVersion = "1.0.0-rc1-update1" + $netCliVersion = "1.0.0-preview1-002702" $baseDir = resolve-path .. $buildDir = "$baseDir\Build" @@ -22,9 +22,9 @@ $workingDir = "$baseDir\$workingName" $workingSourceDir = "$workingDir\Src" $builds = @( - @{Name = "Newtonsoft.Json.Dotnet"; TestsName = "Newtonsoft.Json.Tests.Dotnet"; BuildFunction = "DnxBuild"; TestsFunction = "DnxTests"; Constants="dotnet"; FinalDir=$null; NuGetDir = $null; Framework=$null}, + @{Name = "Newtonsoft.Json.Dotnet"; TestsName = "Newtonsoft.Json.Tests.Dotnet"; BuildFunction = "NetCliBuild"; TestsFunction = "NetCliTests"; Constants="dotnet"; FinalDir="netstandard1.0"; NuGetDir = "netstandard1.0"; Framework=$null}, @{Name = "Newtonsoft.Json"; TestsName = "Newtonsoft.Json.Tests"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants=""; FinalDir="Net45"; NuGetDir = "net45"; Framework="net-4.0"}, - @{Name = "Newtonsoft.Json.Portable"; TestsName = "Newtonsoft.Json.Tests.Portable"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants="PORTABLE"; FinalDir="Portable"; NuGetDir = "portable-net45+wp80+win8+wpa81+dnxcore50"; Framework="net-4.0"}, + @{Name = "Newtonsoft.Json.Portable"; TestsName = "Newtonsoft.Json.Tests.Portable"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants="PORTABLE"; FinalDir="Portable"; NuGetDir = "portable-net45+wp80+win8+wpa81"; Framework="net-4.0"}, @{Name = "Newtonsoft.Json.Portable40"; TestsName = "Newtonsoft.Json.Tests.Portable40"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants="PORTABLE40"; FinalDir="Portable40"; NuGetDir = "portable-net40+sl5+wp80+win8+wpa81"; Framework="net-4.0"}, @{Name = "Newtonsoft.Json.Net40"; TestsName = "Newtonsoft.Json.Tests.Net40"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants="NET40"; FinalDir="Net40"; NuGetDir = "net40"; Framework="net-4.0"}, @{Name = "Newtonsoft.Json.Net35"; TestsName = "Newtonsoft.Json.Tests.Net35"; BuildFunction = "MSBuildBuild"; TestsFunction = "NUnitTests"; Constants="NET35"; FinalDir="Net35"; NuGetDir = "net35"; Framework="net-2.0"}, @@ -90,11 +90,7 @@ task Package -depends Build { if ($buildNuGet) { - $nugetVersion = $majorWithReleaseVersion - if ($nugetPrelease -ne $null) - { - $nugetVersion = $nugetVersion + "-" + $nugetPrelease - } + $nugetVersion = GetNuGetVersion New-Item -Path $workingDir\NuGet -ItemType Directory @@ -136,6 +132,7 @@ task Package -depends Build { Write-Host exec { .\Tools\NuGet\NuGet.exe pack $nuspecPath -Symbols } + exec { dotnet pack $workingSourceDir\Newtonsoft.Json\project.json -c Release } move -Path .\*.nupkg -Destination $workingDir\NuGet } @@ -204,36 +201,32 @@ function MSBuildBuild($build) exec { msbuild "/t:Clean;Rebuild" /p:Configuration=Release "/p:CopyNuGetImplementations=true" "/p:Platform=Any CPU" "/p:PlatformTarget=AnyCPU" /p:OutputPath=bin\Release\$finalDir\ /p:AssemblyOriginatorKeyFile=$signKeyPath "/p:SignAssembly=$signAssemblies" "/p:TreatWarningsAsErrors=$treatWarningsAsErrors" "/p:VisualStudioVersion=14.0" /p:DefineConstants=`"$constants`" "$workingSourceDir\$name.sln" | Out-Default } "Error building $name" } -function DnxBuild($build) +function NetCliBuild($build) { $name = $build.Name $projectPath = "$workingSourceDir\Newtonsoft.Json\project.json" - exec { dnvm install $dnvmVersion -r clr | Out-Default } - exec { dnvm use $dnvmVersion -r clr | Out-Default } + exec { .\Tools\Dotnet\install.ps1 -Version $netCliVersion | Out-Default } + exec { dotnet --version | Out-Default } Write-Host -ForegroundColor Green "Restoring packages for $name" Write-Host - exec { dnu restore $projectPath | Out-Default } + exec { dotnet restore $projectPath | Out-Default } Write-Host -ForegroundColor Green "Building $projectPath" - exec { dnu build $projectPath --configuration Release | Out-Default } + exec { dotnet build $projectPath -f netstandard1.0 -c Release -o bin\Release\netstandard1.0 | Out-Default } } -function DnxTests($build) +function NetCliTests($build) { $name = $build.TestsName - #Write-Host -ForegroundColor Green "Ensuring latest CoreCLR is installed for $name" - #Write-Host - #exec { & $toolsDir\Kvm\kvm.ps1 upgrade -r CoreCLR -NoNative | Out-Default } - - exec { dnvm install $dnvmVersion -r coreclr | Out-Default } - exec { dnvm use $dnvmVersion -r coreclr | Out-Default } + exec { .\Tools\Dotnet\install.ps1 -Version $netCliVersion | Out-Default } + exec { dotnet --version | Out-Default } Write-Host -ForegroundColor Green "Restoring packages for $name" Write-Host - exec { dnu restore "$workingSourceDir\Newtonsoft.Json.Tests\project.json" | Out-Default } + exec { dotnet restore "$workingSourceDir\Newtonsoft.Json.Tests\project.json" | Out-Default } Write-Host -ForegroundColor Green "Ensuring test project builds for $name" Write-Host @@ -241,7 +234,7 @@ function DnxTests($build) try { Set-Location "$workingSourceDir\Newtonsoft.Json.Tests" - exec { dnx --configuration Release test | Out-Default } + exec { dotnet test "$workingSourceDir\Newtonsoft.Json.Tests\project.json" -f netcoreapp1.0 -c Release -parallel none | Out-Default } } finally { @@ -266,6 +259,17 @@ function NUnitTests($build) exec { .\Tools\NUnit\nunit-console.exe "$workingDir\Deployed\Bin\$finalDir\Newtonsoft.Json.Tests.dll" /framework=$framework /xml:$workingDir\$name.xml | Out-Default } "Error running $name tests" } +function GetNuGetVersion() +{ + $nugetVersion = $majorWithReleaseVersion + if ($nugetPrerelease -ne $null) + { + $nugetVersion = $nugetVersion + "-" + $nugetPrerelease + } + + return $nugetVersion +} + function GetConstants($constants, $includeSigned) { $signed = switch($includeSigned) { $true { ";SIGNED" } default { "" } } @@ -345,8 +349,10 @@ function Update-Project { $file = switch($sign) { $true { $signKeyPath } default { $null } } $json = (Get-Content $projectPath) -join "`n" | ConvertFrom-Json - $options = @{"warningsAsErrors" = $true; "keyFile" = $file; "define" = ((GetConstants "dotnet" $sign) -split ";") } - Add-Member -InputObject $json -MemberType NoteProperty -Name "compilationOptions" -Value $options -Force + $options = @{"warningsAsErrors" = $true; "xmlDoc" = $true; "keyFile" = $file; "define" = ((GetConstants "dotnet" $sign) -split ";") } + Add-Member -InputObject $json -MemberType NoteProperty -Name "buildOptions" -Value $options -Force + + $json.version = GetNuGetVersion ConvertTo-Json $json -Depth 10 | Set-Content $projectPath } diff --git a/Build/runbuild.cmd b/Build/runbuild.cmd index e6dc8e57..18b460cd 100644 --- a/Build/runbuild.cmd +++ b/Build/runbuild.cmd @@ -1,5 +1,5 @@ cls -powershell -Command "& { [Console]::WindowWidth = 150; [Console]::WindowHeight = 50; Start-Transcript %~dp0runbuild.txt; Import-Module %~dp0..\Tools\PSake\psake.psm1; Invoke-psake %~dp0..\Build\build.ps1 %*; Stop-Transcript; exit !($psake.build_success); }" +powershell -Command "& { [Console]::WindowWidth = 150; [Console]::WindowHeight = 50; Start-Transcript '%~dp0runbuild.txt'; Import-Module '%~dp0..\Tools\PSake\psake.psm1'; Invoke-psake '%~dp0..\Build\build.ps1' %*; Stop-Transcript; exit !($psake.build_success); }" ECHO %ERRORLEVEL% EXIT /B %ERRORLEVEL% \ No newline at end of file diff --git a/Doc/JsonNetVsDotNetSerializers.aml b/Doc/JsonNetVsDotNetSerializers.aml index 4edc82c2..9beff0d9 100644 --- a/Doc/JsonNetVsDotNetSerializers.aml +++ b/Doc/JsonNetVsDotNetSerializers.aml @@ -431,7 +431,7 @@ - Serailizes Entity Framework + Serializes Entity Framework @@ -499,4 +499,4 @@ - \ No newline at end of file + diff --git a/Src/Newtonsoft.Json.TestConsole/Program.cs b/Src/Newtonsoft.Json.TestConsole/Program.cs index 051a5e65..9df1c254 100644 --- a/Src/Newtonsoft.Json.TestConsole/Program.cs +++ b/Src/Newtonsoft.Json.TestConsole/Program.cs @@ -31,6 +31,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Script.Serialization; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Tests; using Newtonsoft.Json.Tests.Converters; @@ -52,6 +53,7 @@ namespace Newtonsoft.Json.TestConsole //t.DeserializeLargeJson(); //PerformanceTests t = new PerformanceTests(); + LargeArrayJTokenPathPerformance(); //t.Iterations = 50000; //t.BenchmarkDeserializeMethod(PerformanceTests.SerializeMethod.JsonNet, PerformanceTests.JsonText); @@ -62,7 +64,7 @@ namespace Newtonsoft.Json.TestConsole //ReadLargeJson(); //WriteLargeJson(); - DeserializeJson(); + //DeserializeJson(); //ReadLargeJson(); //ReadLargeJsonJavaScriptSerializer(); @@ -72,6 +74,28 @@ namespace Newtonsoft.Json.TestConsole Console.ReadKey(); } + public static void LargeArrayJTokenPathPerformance() + { + JArray a = new JArray(); + for (int i = 0; i < 100000; i++) + { + a.Add(i); + } + + JToken last = a.Last; + + int interations = 1000; + + Console.WriteLine("Ready!!!"); + Console.ReadKey(); + + string p = null; + for (int i = 0; i < interations; i++) + { + p = last.Path; + } + } + public static void DeserializeJson() { PerformanceTests t = new PerformanceTests(); diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index 4c1c2c7b..8684df2c 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -130,6 +130,36 @@ namespace Newtonsoft.Json.Tests.Converters } #if !NET20 + [Test] + public void SerializeDollarProperty() + { + string json1 = @"{""$"":""test""}"; + + var doc = JsonConvert.DeserializeXNode(json1); + + Assert.AreEqual(@"<_x0024_>test", doc.ToString()); + + var json2 = JsonConvert.SerializeXNode(doc); + + Assert.AreEqual(json1, json2); + } + + [Test] + public void SerializeNonKnownDollarProperty() + { + string json1 = @"{""$JELLY"":""test""}"; + + var doc = JsonConvert.DeserializeXNode(json1); + + Console.WriteLine(doc.ToString()); + + Assert.AreEqual(@"<_x0024_JELLY>test", doc.ToString()); + + var json2 = JsonConvert.SerializeXNode(doc); + + Assert.AreEqual(json1, json2); + } + public class MyModel { public string MyProperty { get; set; } @@ -2670,6 +2700,58 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual("null", json); } + + [Test] + public void SerializeElementExplicitAttributeNamespace() + { + var original = XElement.Parse(""); + Assert.AreEqual(@"", original.ToString()); + + var json = JsonConvert.SerializeObject(original); + Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); + + var deserialized = JsonConvert.DeserializeObject(json); + Assert.AreEqual(@"", deserialized.ToString()); + } + + [Test] + public void SerializeElementImplicitAttributeNamespace() + { + var original = new XElement("{http://example.com}MyElement"); + Assert.AreEqual(@"", original.ToString()); + + var json = JsonConvert.SerializeObject(original); + Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); + + var deserialized = JsonConvert.DeserializeObject(json); + Assert.AreEqual(@"", deserialized.ToString()); + } + + [Test] + public void SerializeDocumentExplicitAttributeNamespace() + { + var original = XDocument.Parse(""); + Assert.AreEqual(@"", original.ToString()); + + var json = JsonConvert.SerializeObject(original); + Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); + + var deserialized = JsonConvert.DeserializeObject(json); + Assert.AreEqual(@"", deserialized.ToString()); + } + + [Test] + public void SerializeDocumentImplicitAttributeNamespace() + { + var original = new XDocument(new XElement("{http://example.com}MyElement")); + Assert.AreEqual(@"", original.ToString()); + + var json = JsonConvert.SerializeObject(original); + Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); + + var deserialized = JsonConvert.DeserializeObject(json); + Assert.AreEqual(@"", deserialized.ToString()); + } #endif } } diff --git a/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs index f3cd803f..c43a4c05 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs @@ -54,20 +54,22 @@ using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; namespace Newtonsoft.Json.Tests.Documentation { - public class ConvertingJsonAndXmlTests + [TestFixture] + public class ConvertingJsonAndXmlTests : TestFixtureBase { + [Test] public void SerializeXmlNode() { #region SerializeXmlNode string xml = @" - Alan - http://www.google.com + Alan + http://www.google.com - Louis - http://www.yahoo.com + Louis + http://www.yahoo.com "; @@ -98,6 +100,7 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void DeserializeXmlNode() { #region DeserializeXmlNode @@ -126,17 +129,18 @@ namespace Newtonsoft.Json.Tests.Documentation // // // - // Alan - // http://www.google.com + // Alan + // http://www.google.com // // - // Louis - // http://www.yahoo.com + // Louis + // http://www.yahoo.com // // #endregion } + [Test] public void ForceJsonArray() { #region ForceJsonArray diff --git a/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs index 6ee92436..6ae04a70 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs @@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Tests.Documentation { public static StreamReader OpenText(string path) { - return null; + return new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes("{}"))); } public static StreamWriter CreateText(string path) @@ -76,7 +76,8 @@ namespace Newtonsoft.Json.Tests.Documentation } } - public class LinqToJsonTests + [TestFixture] + public class LinqToJsonTests : TestFixtureBase { public void LinqToJsonBasic() { @@ -129,9 +130,10 @@ namespace Newtonsoft.Json.Tests.Documentation private List GetPosts() { - return null; + return new List(); } + [Test] public void LinqToJsonCreateDeclaratively() { #region LinqToJsonCreateDeclaratively @@ -163,7 +165,7 @@ namespace Newtonsoft.Json.Tests.Documentation // "channel": { // "title": "James Newton-King", // "link": "http://james.newtonking.com", - // "description": "James Newton-King's blog.", + // "description": "James Newton-King\'s blog.", // "item": [ // { // "title": "Json.NET 1.3 + New license + Now on CodePlex", @@ -189,9 +191,10 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonCreateFromObject() { - List posts = null; + List posts = GetPosts(); #region LinqToJsonCreateFromObject JObject o = JObject.FromObject(new @@ -216,6 +219,7 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonCreateParse() { #region LinqToJsonCreateParse @@ -231,6 +235,7 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonCreateParseArray() { #region LinqToJsonCreateParseArray @@ -244,6 +249,7 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonReadObject() { #region LinqToJsonReadObject @@ -255,6 +261,7 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonSimpleQuerying() { #region LinqToJsonSimpleQuerying @@ -262,7 +269,7 @@ namespace Newtonsoft.Json.Tests.Documentation 'channel': { 'title': 'James Newton-King', 'link': 'http://james.newtonking.com', - 'description': 'James Newton-King's blog.', + 'description': 'James Newton-King\'s blog.', 'item': [ { 'title': 'Json.NET 1.3 + New license + Now on CodePlex', @@ -303,9 +310,36 @@ namespace Newtonsoft.Json.Tests.Documentation #endregion } + [Test] public void LinqToJsonQuerying() { - JObject rss = new JObject(); + JObject rss = JObject.Parse(@"{ + 'channel': { + 'title': 'James Newton-King', + 'link': 'http://james.newtonking.com', + 'description': 'James Newton-King\'s blog.', + 'item': [ + { + 'title': 'Json.NET 1.3 + New license + Now on CodePlex', + 'description': 'Annoucing the release of Json.NET 1.3, the MIT license and the source on CodePlex', + 'link': 'http://james.newtonking.com/projects/json-net.aspx', + 'categories': [ + 'Json.NET', + 'CodePlex' + ] + }, + { + 'title': 'LINQ to JSON beta', + 'description': 'Annoucing LINQ to JSON', + 'link': 'http://james.newtonking.com/projects/json-net.aspx', + 'categories': [ + 'Json.NET', + 'LINQ' + ] + } + ] + } + }"); #region LinqToJsonQuerying var postTitles = @@ -321,7 +355,7 @@ namespace Newtonsoft.Json.Tests.Documentation //Json.NET 1.3 + New license + Now on CodePlex var categories = - from c in rss["channel"]["item"].Children()["category"].Values() + from c in rss["channel"]["item"].SelectMany(i => i["categories"]).Values() group c by c into g orderby g.Count() descending @@ -336,6 +370,9 @@ namespace Newtonsoft.Json.Tests.Documentation //LINQ - Count: 1 //CodePlex - Count: 1 #endregion + + Assert.AreEqual(2, postTitles.Count()); + Assert.AreEqual(3, categories.Count()); } #region LinqToJsonDeserializeObject @@ -354,6 +391,7 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void LinqToJsonDeserializeExample() { #region LinqToJsonDeserializeExample @@ -362,9 +400,10 @@ namespace Newtonsoft.Json.Tests.Documentation 'original': 'http://www.foo.com/', 'short': 'krehqk', 'error': { - 'code':0, - 'msg':'No action taken' + 'code': 0, + 'msg': 'No action taken' } + } }"; JObject json = JObject.Parse(jsonText); @@ -386,17 +425,53 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(shortie.Error.ErrorMessage); // No action taken #endregion + + Assert.AreEqual("http://www.foo.com/", shortie.Original); + Assert.AreEqual("No action taken", shortie.Error.ErrorMessage); } + [Test] public void SelectTokenSimple() { - JObject o = new JObject(); + JObject o = JObject.Parse(@"{ + 'Stores': [ + 'Lambton Quay', + 'Willis Street' + ], + 'Manufacturers': [ + { + 'Name': 'Acme Co', + 'Products': [ + { + 'Name': 'Anvil', + 'Price': 50 + } + ] + }, + { + 'Name': 'Contoso', + 'Products': [ + { + 'Name': 'Elbow Grease', + 'Price': 99.95 + }, + { + 'Name': 'Headlight Fluid', + 'Price': 4 + } + ] + } + ] + }"); #region SelectTokenSimple string name = (string)o.SelectToken("Manufacturers[0].Name"); #endregion + + Assert.AreEqual("Acme Co", name); } + [Test] public void SelectTokenComplex() { #region SelectTokenComplex @@ -440,11 +515,45 @@ namespace Newtonsoft.Json.Tests.Documentation string productName = (string)o.SelectToken("Manufacturers[1].Products[0].Name"); // Elbow Grease #endregion + + Assert.AreEqual("Acme Co", name); + Assert.AreEqual(50m, productPrice); + Assert.AreEqual("Elbow Grease", productName); } + [Test] public void SelectTokenLinq() { - JObject o = new JObject(); + JObject o = JObject.Parse(@"{ + 'Stores': [ + 'Lambton Quay', + 'Willis Street' + ], + 'Manufacturers': [ + { + 'Name': 'Acme Co', + 'Products': [ + { + 'Name': 'Anvil', + 'Price': 50 + } + ] + }, + { + 'Name': 'Contoso', + 'Products': [ + { + 'Name': 'Elbow Grease', + 'Price': 99.95 + }, + { + 'Name': 'Headlight Fluid', + 'Price': 4 + } + ] + } + ] + }"); #region SelectTokenLinq IList storeNames = o.SelectToken("Stores").Select(s => (string)s).ToList(); @@ -458,6 +567,10 @@ namespace Newtonsoft.Json.Tests.Documentation decimal totalPrice = o["Manufacturers"].Sum(m => (decimal)m.SelectToken("Products[0].Price")); // 149.95 #endregion + + Assert.AreEqual(2, storeNames.Count); + Assert.AreEqual(2, firstProductNames.Count); + Assert.AreEqual(149.95m, totalPrice); } } } diff --git a/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs index de53557f..8861d22d 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs @@ -53,8 +53,10 @@ using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; namespace Newtonsoft.Json.Tests.Documentation { - public class SerializationTests + [TestFixture] + public class SerializationTests : TestFixtureBase { + [Test] public void SerializeObject() { #region SerializeObject @@ -79,6 +81,8 @@ namespace Newtonsoft.Json.Tests.Documentation Product deserializedProduct = JsonConvert.DeserializeObject(output); #endregion + + Assert.AreEqual("Apple", deserializedProduct.Name); } public void JsonSerializerToStream() @@ -175,6 +179,7 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void SerializationCallbacksExample() { #region SerializationCallbacksExample @@ -216,8 +221,11 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(obj.Member4); // This value was set after deserialization. #endregion + + Assert.AreEqual(11, obj.Member1); } + [Test] public void SerializationErrorHandling() { #region SerializationErrorHandling @@ -251,8 +259,11 @@ namespace Newtonsoft.Json.Tests.Documentation // Unexpected token parsing date. Expected String, got StartArray. // Cannot convert null value to System.DateTime. #endregion + + Assert.AreEqual(new DateTime(2009, 9, 9, 0, 0, 0, DateTimeKind.Utc), c[0]); } + [Test] public void SerializationErrorHandlingWithParent() { #region SerializationErrorHandlingWithParent @@ -302,6 +313,7 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void SerializationErrorHandlingAttributeExample() { #region SerializationErrorHandlingAttributeExample @@ -322,6 +334,12 @@ namespace Newtonsoft.Json.Tests.Documentation // "Title": "Mister Manager" //} #endregion + + StringAssert.AreEqual(@"{ + ""Name"": ""George Michael Bluth"", + ""Age"": 16, + ""Title"": ""Mister Manager"" +}", json); } public void PreservingObjectReferencesOff() @@ -352,11 +370,33 @@ namespace Newtonsoft.Json.Tests.Documentation // } //] #endregion + + StringAssert.AreEqual(@"[ + { + ""Name"": ""James"", + ""BirthDate"": ""1980-12-23T00:00:00Z"", + ""LastModified"": ""2009-02-20T12:59:21Z"" + }, + { + ""Name"": ""James"", + ""BirthDate"": ""1980-12-23T00:00:00Z"", + ""LastModified"": ""2009-02-20T12:59:21Z"" + } +]", json); } + [Test] public void PreservingObjectReferencesOn() { - List people = new List(); + Person p = new Person + { + Name = "James" + }; + List people = new List + { + p, + p + }; #region PreservingObjectReferencesOn string json = JsonConvert.SerializeObject(people, Formatting.Indented, @@ -391,6 +431,8 @@ namespace Newtonsoft.Json.Tests.Documentation bool equal = Object.ReferenceEquals(p1, p2); // true #endregion + + Assert.AreEqual(true, equal); } #region PreservingObjectReferencesAttribute @@ -429,9 +471,25 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void CustomCreationConverterExample() { - string json = null; + string json = @"[ + { + ""FirstName"": ""Maurice"", + ""LastName"": ""Moss"", + ""BirthDate"": ""1981-03-08T00:00Z"", + ""Department"": ""IT"", + ""JobTitle"": ""Support"" + }, + { + ""FirstName"": ""Jen"", + ""LastName"": ""Barber"", + ""BirthDate"": ""1985-12-10T00:00Z"", + ""Department"": ""IT"", + ""JobTitle"": ""Manager"" + } +]"; #region CustomCreationConverterExample //[ @@ -466,8 +524,11 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(employee.JobTitle); // Support #endregion + + Assert.AreEqual("Support", employee.JobTitle); } + [Test] public void ContractResolver() { #region ContractResolver @@ -488,7 +549,7 @@ namespace Newtonsoft.Json.Tests.Documentation //{ // "name": "Widget", - // "expiryDate": "2010-12-20T18:01Z", + // "expiryDate": "2010-12-20T18:01:00Z", // "price": 9.99, // "sizes": [ // "Small", @@ -497,8 +558,20 @@ namespace Newtonsoft.Json.Tests.Documentation // ] //} #endregion + + Assert.AreEqual(@"{ + ""name"": ""Widget"", + ""expiryDate"": ""2010-12-20T18:01:00Z"", + ""price"": 9.99, + ""sizes"": [ + ""Small"", + ""Medium"", + ""Large"" + ] +}", json); } + [Test] public void SerializingCollectionsSerializing() { #region SerializingCollectionsSerializing @@ -523,20 +596,36 @@ namespace Newtonsoft.Json.Tests.Documentation //[ // { // "Name": "Product 1", - // "ExpiryDate": "2000-12-29T00:00Z", + // "ExpiryDate": "2000-12-29T00:00:00Z", // "Price": 99.95, // "Sizes": null // }, // { // "Name": "Product 2", - // "ExpiryDate": "2009-07-31T00:00Z", + // "ExpiryDate": "2009-07-31T00:00:00Z", // "Price": 12.50, // "Sizes": null // } //] #endregion + + Assert.AreEqual(@"[ + { + ""Name"": ""Product 1"", + ""ExpiryDate"": ""2000-12-29T00:00:00Z"", + ""Price"": 99.95, + ""Sizes"": null + }, + { + ""Name"": ""Product 2"", + ""ExpiryDate"": ""2009-07-31T00:00:00Z"", + ""Price"": 12.50, + ""Sizes"": null + } +]", json); } + [Test] public void SerializingCollectionsDeserializing() { #region SerializingCollectionsDeserializing @@ -565,8 +654,11 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(p1.Name); // Product 1 #endregion + + Assert.AreEqual("Product 1", p1.Name); } + [Test] public void SerializingCollectionsDeserializingDictionaries() { #region SerializingCollectionsDeserializingDictionaries @@ -580,6 +672,8 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(values["key1"]); // value1 #endregion + + Assert.AreEqual("value1", values["key1"]); } #region SerializingDatesInJson @@ -658,6 +752,7 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void ReducingSerializedJsonSizeNullValueHandlingExample() { #region ReducingSerializedJsonSizeNullValueHandlingExample @@ -687,6 +782,20 @@ namespace Newtonsoft.Json.Tests.Documentation // "Description": "It's no Bad Boys" // } #endregion + + Assert.AreEqual(@"{ + ""Name"": ""Bad Boys III"", + ""Description"": ""It's no Bad Boys"", + ""Classification"": null, + ""Studio"": null, + ""ReleaseDate"": null, + ""ReleaseCountries"": null +}", included); + + Assert.AreEqual(@"{ + ""Name"": ""Bad Boys III"", + ""Description"": ""It's no Bad Boys"" +}", ignored); } #region ReducingSerializedJsonSizeDefaultValueHandlingObject @@ -744,6 +853,20 @@ namespace Newtonsoft.Json.Tests.Documentation // "Amount": 50.0 // } #endregion + + Assert.AreEqual(@"{ + ""Company"": ""Acme Ltd."", + ""Amount"": 50.0, + ""Paid"": false, + ""PaidDate"": null, + ""FollowUpDays"": 30, + ""FollowUpEmailAddress"": """" +}", included); + + Assert.AreEqual(@"{ + ""Company"": ""Acme Ltd."", + ""Amount"": 50.0 +}", included); } #region ReducingSerializedJsonSizeContractResolverObject @@ -807,6 +930,17 @@ namespace Newtonsoft.Json.Tests.Documentation // "BookPrice": 16.19 // } #endregion + + Assert.AreEqual(@"{ + ""AuthorName"": ""Brandon Sanderson"", + ""AuthorAge"": 34, + ""AuthorCountry"": ""United States of America"" +}", startingWithA); + + Assert.AreEqual(@"{ + ""BookName"": ""The Gathering Storm"", + ""BookPrice"": 16.19 +}", startingWithB); } #region SerializingPartialJsonFragmentsObject @@ -818,6 +952,7 @@ namespace Newtonsoft.Json.Tests.Documentation } #endregion + [Test] public void SerializingPartialJsonFragmentsExample() { #region SerializingPartialJsonFragmentsExample @@ -894,8 +1029,11 @@ namespace Newtonsoft.Json.Tests.Documentation // Content = Self: Zoolander. Socialite Paris Hilton... // Url = http://www.imdb.com/name/nm0385296/ #endregion + + Assert.AreEqual("Paris Hilton - Wikipedia, the free encyclopedia", searchResults[0].Title); } + [Test] public void SerializeMultidimensionalArrayExample() { string[,] famousCouples = new string[,] @@ -918,6 +1056,8 @@ namespace Newtonsoft.Json.Tests.Documentation Console.WriteLine(deserialized[3, 0] + ", " + deserialized[3, 1]); // Han, Leia + + Assert.AreEqual("Han", deserialized[3, 0]); } } } diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index d043d7e0..853daeae 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -61,6 +61,126 @@ namespace Newtonsoft.Json.Tests [TestFixture] public class JsonTextReaderTest : TestFixtureBase { + [Test] + public void Float_NaN_Read() + { + const string testJson = "{float: NaN}"; + + JsonTextReader reader = new JsonTextReader(new StringReader(testJson)); + + Assert.IsTrue(reader.Read()); + Assert.IsTrue(reader.Read()); + Assert.IsTrue(reader.Read()); + + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(double.NaN, reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.IsFalse(reader.Read()); + } + + [Test] + public void Float_NaN_ReadAsInt32() + { + const string testJson = "{float: NaN}"; + + JsonTextReader reader = new JsonTextReader(new StringReader(testJson)); + + Assert.IsTrue(reader.Read()); + Assert.IsTrue(reader.Read()); + + ExceptionAssert.Throws(() => reader.ReadAsInt32(), "Cannot read NaN value. Path 'float', line 1, position 11."); + } + + [Test] + public void Float_NaNAndInifinity_ReadAsDouble() + { + const string testJson = @"[ + NaN, + Infinity, + -Infinity +]"; ; + + JsonTextReader reader = new JsonTextReader(new StringReader(testJson)); + + Assert.IsTrue(reader.Read()); + + Assert.AreEqual(double.NaN, reader.ReadAsDouble()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(double.NaN, reader.Value); + + Assert.AreEqual(double.PositiveInfinity, reader.ReadAsDouble()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(double.PositiveInfinity, reader.Value); + + Assert.AreEqual(double.NegativeInfinity, reader.ReadAsDouble()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(double.NegativeInfinity, reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.IsFalse(reader.Read()); + } + + [Test] + public void Float_NaNAndInifinity_ReadAsString() + { + const string testJson = @"[ + NaN, + Infinity, + -Infinity +]"; ; + + JsonTextReader reader = new JsonTextReader(new StringReader(testJson)); + + Assert.IsTrue(reader.Read()); + + Assert.AreEqual(JsonConvert.NaN, reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(JsonConvert.NaN, reader.Value); + + Assert.AreEqual(JsonConvert.PositiveInfinity, reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(JsonConvert.PositiveInfinity, reader.Value); + + Assert.AreEqual(JsonConvert.NegativeInfinity, reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual(JsonConvert.NegativeInfinity, reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.IsFalse(reader.Read()); + } + + [Test] + public void FloatParseHandling_ReadAsString() + { + string json = "[9223372036854775807, 1.7976931348623157E+308, 792281625142643375935439503.35, 792281625142643375935555555555555555555555555555555555555555555555555439503.35]"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.FloatParseHandling = Json.FloatParseHandling.Decimal; + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.AreEqual("9223372036854775807", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("9223372036854775807", reader.Value); + + Assert.AreEqual("1.7976931348623157E+308", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("1.7976931348623157E+308", reader.Value); + + Assert.AreEqual("792281625142643375935439503.35", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("792281625142643375935439503.35", reader.Value); + + Assert.AreEqual("792281625142643375935555555555555555555555555555555555555555555555555439503.35", reader.ReadAsString()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + Assert.AreEqual("792281625142643375935555555555555555555555555555555555555555555555555439503.35", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + } + [Test] public void LineInfoAndNewLines() { @@ -455,7 +575,7 @@ third line", jsonTextReader.Value); Assert.IsTrue(reader.Read()); Assert.AreEqual(JsonToken.StartArray, reader.TokenType); - ExceptionAssert.Throws(() => reader.Read(), "Cannot read NaN as a decimal."); + ExceptionAssert.Throws(() => reader.Read(), "Cannot read NaN value. Path '', line 1, position 4."); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs index 1a54f5c1..e459fa1c 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs @@ -51,6 +51,20 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class JTokenReaderTest : TestFixtureBase { +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) + [Test] + public void ConvertBigIntegerToDouble() + { + var jObject = JObject.Parse("{ maxValue:10000000000000000000}"); + + JsonReader reader = jObject.CreateReader(); + Assert.IsTrue(reader.Read()); + Assert.IsTrue(reader.Read()); + Assert.AreEqual(10000000000000000000d, reader.ReadAsDouble()); + Assert.IsTrue(reader.Read()); + } +#endif + [Test] public void ErrorTokenIndex() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs index 4ca7519c..174ec9c1 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs @@ -249,6 +249,100 @@ namespace Newtonsoft.Json.Tests.Linq ]", writer.Token.ToString()); } + [Test] + public void WriteTokenWithParent() + { + JObject o = new JObject + { + ["prop1"] = new JArray(1), + ["prop2"] = 1 + }; + + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartArray(); + + writer.WriteToken(o.CreateReader()); + + Assert.AreEqual(WriteState.Array, writer.WriteState); + + writer.WriteEndArray(); + + Console.WriteLine(writer.Token.ToString()); + + StringAssert.AreEqual(@"[ + { + ""prop1"": [ + 1 + ], + ""prop2"": 1 + } +]", writer.Token.ToString()); + } + + [Test] + public void WriteTokenWithPropertyParent() + { + JValue v = new JValue(1); + + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartObject(); + writer.WritePropertyName("Prop1"); + + writer.WriteToken(v.CreateReader()); + + Assert.AreEqual(WriteState.Object, writer.WriteState); + + writer.WriteEndObject(); + + StringAssert.AreEqual(@"{ + ""Prop1"": 1 +}", writer.Token.ToString()); + } + + [Test] + public void WriteValueTokenWithParent() + { + JValue v = new JValue(1); + + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartArray(); + + writer.WriteToken(v.CreateReader()); + + Assert.AreEqual(WriteState.Array, writer.WriteState); + + writer.WriteEndArray(); + + StringAssert.AreEqual(@"[ + 1 +]", writer.Token.ToString()); + } + + [Test] + public void WriteEmptyToken() + { + JObject o = new JObject(); + JsonReader reader = o.CreateReader(); + while (reader.Read()) + { + } + + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartArray(); + + writer.WriteToken(reader); + + Assert.AreEqual(WriteState.Array, writer.WriteState); + + writer.WriteEndArray(); + + StringAssert.AreEqual(@"[]", writer.Token.ToString()); + } + [Test] public void WriteRawValue() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs index 49f473d0..81c6cdc1 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs @@ -902,5 +902,52 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath Assert.AreEqual("Headlight Fluid", firstProductNames[1]); Assert.AreEqual(149.95m, totalPrice); } + + [Test] + public void NotEqualsAndNonPrimativeValues() + { + string json = @"[ + { + ""name"": ""string"", + ""value"": ""aString"" + }, + { + ""name"": ""number"", + ""value"": 123 + }, + { + ""name"": ""array"", + ""value"": [ + 1, + 2, + 3, + 4 + ] + }, + { + ""name"": ""object"", + ""value"": { + ""1"": 1 + } + } +]"; + + JArray a = JArray.Parse(json); + + List result = a.SelectTokens("$.[?(@.value!=1)]").ToList(); + Assert.AreEqual(4, result.Count); + + result = a.SelectTokens("$.[?(@.value!='2000-12-05T05:07:59-10:00')]").ToList(); + Assert.AreEqual(4, result.Count); + + result = a.SelectTokens("$.[?(@.value!=null)]").ToList(); + Assert.AreEqual(4, result.Count); + + result = a.SelectTokens("$.[?(@.value!=123)]").ToList(); + Assert.AreEqual(3, result.Count); + + result = a.SelectTokens("$.[?(@.value)]").ToList(); + Assert.AreEqual(4, result.Count); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs index a9b7f569..5ac8c2eb 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs @@ -55,6 +55,46 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class LinqToJsonTest : TestFixtureBase { + [Test] + public void FromObjectGuid() + { + var token1 = new JValue(Guid.NewGuid()); + var token2 = JToken.FromObject(token1); + Assert.IsTrue(JToken.DeepEquals(token1, token2)); + Assert.AreEqual(token1.Type, token2.Type); + } + + [Test] + public void FromObjectTimeSpan() + { + var token1 = new JValue(TimeSpan.FromDays(1)); + var token2 = JToken.FromObject(token1); + Assert.IsTrue(JToken.DeepEquals(token1, token2)); + Assert.AreEqual(token1.Type, token2.Type); + } + + [Test] + public void FromObjectUri() + { + var token1 = new JValue(new Uri("http://www.newtonsoft.com")); + var token2 = JToken.FromObject(token1); + Assert.IsTrue(JToken.DeepEquals(token1, token2)); + Assert.AreEqual(token1.Type, token2.Type); + } + + [Test] + public void ToObject_Guid() + { + JObject anon = new JObject + { + ["id"] = Guid.NewGuid() + }; + Assert.AreEqual(JTokenType.Guid, anon["id"].Type); + + Dictionary dict = anon.ToObject>(); + Assert.AreEqual(JTokenType.Guid, dict["id"].Type); + } + public class TestClass_ULong { public ulong Value { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Dotnet.xproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Dotnet.xproj index f3c3d980..e2efa374 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Dotnet.xproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Dotnet.xproj @@ -9,9 +9,8 @@ 13e906ae-5a47-4354-8caf-e63e8ac541ed Newtonsoft.Json.Tests ..\artifacts\obj\$(MSBuildProjectName) - ..\artifacts\bin\$(MSBuildProjectName)\ + .\bin\ - 2.0 diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj index 648bf706..c8c6da9b 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj @@ -171,15 +171,15 @@ - + - - - - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj index d5fa425b..9c34acac 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj @@ -202,12 +202,12 @@ - - + + - + @@ -232,8 +232,8 @@ - - + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj index f0cdaacf..fc5de9b0 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj @@ -318,7 +318,7 @@ - + @@ -346,10 +346,10 @@ - - - - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj index b39e015c..d1fcb3f5 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj @@ -193,7 +193,7 @@ - + @@ -221,10 +221,10 @@ - - - - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj index 0b84de7d..ddc70846 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj @@ -197,7 +197,7 @@ - + @@ -225,10 +225,10 @@ - - - - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 0d74f34c..c8e864e2 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -383,7 +383,7 @@ - + @@ -392,10 +392,10 @@ - - - - + + + + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json index 51db2f8c..ffdaaa2c 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json @@ -3,7 +3,7 @@ "Autofac": "4.0.0-beta7-130", "FSharp.Core": "4.0.0.1", "NUnit": "2.6.2", - "System.Buffers": "4.0.0-rc2-23826", + "System.Buffers": "4.0.0-rc2-24027", "System.Collections.Immutable": "1.1.37" }, "frameworks": { diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index 16f39448..7fdd7ec7 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -23,10 +23,9 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET20 || NET35 || NET40 || NETFX_CORE || PORTABLE || PORTABLE40 || DNXCORE50) +#if !(NET20 || NET35 || NET40 || NETFX_CORE || PORTABLE40 || DNXCORE50) using System.Xml; using System; -using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Globalization; @@ -258,6 +257,7 @@ namespace Newtonsoft.Json.Tests } #if !(PORTABLE40) +#if !(PORTABLE) [Test] public void ConvertXmlNode() { @@ -269,6 +269,7 @@ namespace Newtonsoft.Json.Tests JsonConvert.SerializeXmlNode(doc); } +#endif [Test] public void ConvertXNode() @@ -301,6 +302,77 @@ namespace Newtonsoft.Json.Tests return result; } + [Test] + public void LargeArrayJTokenPathPerformance() + { + JArray a = new JArray(); + for (int i = 0; i < 100000; i++) + { + a.Add(i); + } + + JToken first = a.First; + JToken last = a.Last; + + int interations = 1000; + + TimeOperation(() => + { + string p = null; + for (int i = 0; i < interations; i++) + { + p = first.Path; + } + + return p; + }, "First"); + + TimeOperation(() => + { + string p = null; + for (int i = 0; i < interations; i++) + { + p = last.Path; + } + + return p; + }, "Last"); + } + + [Test] + public void LargeArrayAddPerformance() + { + JArray a1 = new JArray(); + + JArray a2 = new JArray(); + for (int i = 0; i < 100000; i++) + { + a2.Add(i); + } + + int interations = 1000; + + TimeOperation(() => + { + for (int i = 0; i < interations; i++) + { + a1.Add(interations); + } + + return a1; + }, "Small"); + + TimeOperation(() => + { + for (int i = 0; i < interations; i++) + { + a2.Add(interations); + } + + return a2; + }, "Large"); + } + [Test] public void BuildJObject() { diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 846978b1..9356d94e 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -31,7 +31,9 @@ using System.Security; // set of attributes. Change these attribute values to modify the information // associated with an assembly. -#if PORTABLE40 +#if NETSTANDARD10 +[assembly: AssemblyTitle("Json.NET Tests .NET Standard 1.0")] +#elif PORTABLE40 [assembly: AssemblyTitle("Json.NET Tests Portable .NET 4.0")] #elif PORTABLE [assembly: AssemblyTitle("Json.NET Tests Portable")] diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ConstructorHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ConstructorHandlingTests.cs index c00cca5e..ca4538b8 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ConstructorHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ConstructorHandlingTests.cs @@ -77,22 +77,22 @@ namespace Newtonsoft.Json.Tests.Serialization } [Test] - public void FailWithPrivateConstructorPlusParametizedAndDefault() + public void FailWithPrivateConstructorPlusParameterizedAndDefault() { ExceptionAssert.Throws(() => { string json = @"{Name:""Name!""}"; - PrivateConstructorWithPublicParametizedConstructorTestClass c = JsonConvert.DeserializeObject(json); + PrivateConstructorWithPublicParameterizedConstructorTestClass c = JsonConvert.DeserializeObject(json); }); } [Test] - public void SuccessWithPrivateConstructorPlusParametizedAndAllowNonPublic() + public void SuccessWithPrivateConstructorPlusParameterizedAndAllowNonPublic() { string json = @"{Name:""Name!""}"; - PrivateConstructorWithPublicParametizedConstructorTestClass c = JsonConvert.DeserializeObject(json, + PrivateConstructorWithPublicParameterizedConstructorTestClass c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor @@ -103,71 +103,71 @@ namespace Newtonsoft.Json.Tests.Serialization } [Test] - public void SuccessWithPublicParametizedConstructor() + public void SuccessWithPublicParameterizedConstructor() { string json = @"{Name:""Name!""}"; - var c = JsonConvert.DeserializeObject(json); + var c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual("Name!", c.Name); } [Test] - public void SuccessWithPublicParametizedConstructorWhenParamaterIsNotAProperty() + public void SuccessWithPublicParameterizedConstructorWhenParameterIsNotAProperty() { string json = @"{nameParameter:""Name!""}"; - PublicParametizedConstructorWithNonPropertyParameterTestClass c = JsonConvert.DeserializeObject(json); + PublicParameterizedConstructorWithNonPropertyParameterTestClass c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual("Name!", c.Name); } [Test] - public void SuccessWithPublicParametizedConstructorWhenParamaterRequiresAConverter() + public void SuccessWithPublicParameterizedConstructorWhenParameterRequiresAConverter() { string json = @"{nameParameter:""Name!""}"; - PublicParametizedConstructorRequiringConverterTestClass c = JsonConvert.DeserializeObject(json, new NameContainerConverter()); + PublicParameterizedConstructorRequiringConverterTestClass c = JsonConvert.DeserializeObject(json, new NameContainerConverter()); Assert.IsNotNull(c); Assert.AreEqual("Name!", c.Name.Value); } [Test] - public void SuccessWithPublicParametizedConstructorWhenParamaterRequiresAConverterWithParameterAttribute() + public void SuccessWithPublicParameterizedConstructorWhenParameterRequiresAConverterWithParameterAttribute() { string json = @"{nameParameter:""Name!""}"; - PublicParametizedConstructorRequiringConverterWithParameterAttributeTestClass c = JsonConvert.DeserializeObject(json); + PublicParameterizedConstructorRequiringConverterWithParameterAttributeTestClass c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual("Name!", c.Name.Value); } [Test] - public void SuccessWithPublicParametizedConstructorWhenParamaterRequiresAConverterWithPropertyAttribute() + public void SuccessWithPublicParameterizedConstructorWhenParameterRequiresAConverterWithPropertyAttribute() { string json = @"{name:""Name!""}"; - PublicParametizedConstructorRequiringConverterWithPropertyAttributeTestClass c = JsonConvert.DeserializeObject(json); + PublicParameterizedConstructorRequiringConverterWithPropertyAttributeTestClass c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual("Name!", c.Name.Value); } [Test] - public void SuccessWithPublicParametizedConstructorWhenParamaterNameConflictsWithPropertyName() + public void SuccessWithPublicParameterizedConstructorWhenParameterNameConflictsWithPropertyName() { string json = @"{name:""1""}"; - PublicParametizedConstructorWithPropertyNameConflict c = JsonConvert.DeserializeObject(json); + PublicParameterizedConstructorWithPropertyNameConflict c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual(1, c.Name); } [Test] - public void PublicParametizedConstructorWithPropertyNameConflictWithAttribute() + public void PublicParameterizedConstructorWithPropertyNameConflictWithAttribute() { string json = @"{name:""1""}"; - PublicParametizedConstructorWithPropertyNameConflictWithAttribute c = JsonConvert.DeserializeObject(json); + PublicParameterizedConstructorWithPropertyNameConflictWithAttribute c = JsonConvert.DeserializeObject(json); Assert.IsNotNull(c); Assert.AreEqual(1, c.Name); } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index 85b3f3ea..f0b9ed75 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -441,12 +441,12 @@ namespace Newtonsoft.Json.Tests.Serialization public void ParameterizedCreator() { var resolver = new DefaultContractResolver(); - var contract = (JsonObjectContract)resolver.ResolveContract(typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute)); + var contract = (JsonObjectContract)resolver.ResolveContract(typeof(PublicParameterizedConstructorWithPropertyNameConflictWithAttribute)); Assert.IsNull(contract.DefaultCreator); Assert.IsNotNull(contract.ParameterizedCreator); #pragma warning disable 618 - Assert.AreEqual(contract.ParametrizedConstructor, typeof(PublicParametizedConstructorWithPropertyNameConflictWithAttribute).GetConstructor(new[] { typeof(string) })); + Assert.AreEqual(contract.ParametrizedConstructor, typeof(PublicParameterizedConstructorWithPropertyNameConflictWithAttribute).GetConstructor(new[] { typeof(string) })); #pragma warning restore 618 Assert.AreEqual(1, contract.CreatorParameters.Count); Assert.AreEqual("name", contract.CreatorParameters[0].PropertyName); @@ -461,12 +461,12 @@ namespace Newtonsoft.Json.Tests.Serialization public void OverrideCreator() { var resolver = new DefaultContractResolver(); - var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParamatrizedConstructorsJsonConstructor)); + var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParametrizedConstructorsJsonConstructor)); Assert.IsNull(contract.DefaultCreator); Assert.IsNotNull(contract.OverrideCreator); #pragma warning disable 618 - Assert.AreEqual(contract.OverrideConstructor, typeof(MultipleParamatrizedConstructorsJsonConstructor).GetConstructor(new[] { typeof(string), typeof(int) })); + Assert.AreEqual(contract.OverrideConstructor, typeof(MultipleParametrizedConstructorsJsonConstructor).GetConstructor(new[] { typeof(string), typeof(int) })); #pragma warning restore 618 Assert.AreEqual(2, contract.CreatorParameters.Count); Assert.AreEqual("Value", contract.CreatorParameters[0].PropertyName); @@ -482,20 +482,20 @@ namespace Newtonsoft.Json.Tests.Serialization public void CustomOverrideCreator() { var resolver = new DefaultContractResolver(); - var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParamatrizedConstructorsJsonConstructor)); + var contract = (JsonObjectContract)resolver.ResolveContract(typeof(MultipleParametrizedConstructorsJsonConstructor)); bool ensureCustomCreatorCalled = false; contract.OverrideCreator = args => { ensureCustomCreatorCalled = true; - return new MultipleParamatrizedConstructorsJsonConstructor((string)args[0], (int)args[1]); + return new MultipleParametrizedConstructorsJsonConstructor((string)args[0], (int)args[1]); }; #pragma warning disable 618 Assert.IsNull(contract.OverrideConstructor); #pragma warning restore 618 - var o = JsonConvert.DeserializeObject("{Value:'value!', Age:1}", new JsonSerializerSettings + var o = JsonConvert.DeserializeObject("{Value:'value!', Age:1}", new JsonSerializerSettings { ContractResolver = resolver }); diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs index 8f4a0a62..ec1092f4 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs @@ -27,7 +27,7 @@ using System; using System.ComponentModel; using System.IO; using System.Runtime.Serialization; -#if !(NET20 || NET35 || NETFX_CORE || PORTABLE) +#if !(NET20 || NET35 || NETFX_CORE || PORTABLE || DNXCORE50) using System.Runtime.Serialization.Json; #endif using System.Text; diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs index 6acc24df..0a366552 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs @@ -374,6 +374,40 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(7, c.ExtensionData.Count); } + [JsonObject(MemberSerialization.OptIn)] + public class MyClass + { + public int NotForJson { get; set; } + + [JsonPropertyAttribute(Required = Required.Always)] + public int ForJson { get; set; } + + [JsonExtensionData(ReadData = true, WriteData = true)] + public IDictionary ExtraInfoJson { get; set; } + + public MyClass(MyClass other = null) + { + if (other != null) + { + // copy construct + } + } + } + + [Test] + public void PopulateWithExtensionData() + { + string jsonStirng = @"{ ""ForJson"" : 33 , ""extra1"" : 11, ""extra2"" : 22 }"; + + MyClass c = new MyClass(); + + JsonConvert.PopulateObject(jsonStirng, c); + + Assert.AreEqual(2, c.ExtraInfoJson.Count); + Assert.AreEqual(11, (int)c.ExtraInfoJson["extra1"]); + Assert.AreEqual(22, (int)c.ExtraInfoJson["extra2"]); + } + public class MultipleExtensionDataAttributesTestClass { public string Name { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs index a7196a4d..b71149ea 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs @@ -1917,6 +1917,86 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(deserializeTest2["testkey"], ""); } #endif + + [Test] + public void DeserializeCollectionWithConstructorArrayArgument() + { + var v = new ReadOnlyCollectionWithArrayArgument(new[] { -0.014147478859765236, -0.011419606805541858, -0.010038461483676238 }); + var json = JsonConvert.SerializeObject(v); + + ExceptionAssert.Throws(() => + { + JsonConvert.DeserializeObject>(json); + }, "Unable to find a constructor to use for type Newtonsoft.Json.Tests.Serialization.ReadOnlyCollectionWithArrayArgument`1[System.Double]. Path '', line 1, position 1."); + } + } + + public class ReadOnlyCollectionWithArrayArgument : IList + { + private readonly IList _values; + + public ReadOnlyCollectionWithArrayArgument(T[] args) + { + _values = args ?? (IList)new List(); + } + + public IEnumerator GetEnumerator() + { + return _values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _values.GetEnumerator(); + } + + public void Add(T item) + { + throw new NotImplementedException(); + } + + public void Clear() + { + throw new NotImplementedException(); + } + + public bool Contains(T item) + { + throw new NotImplementedException(); + } + + public void CopyTo(T[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + public bool Remove(T item) + { + throw new NotImplementedException(); + } + + public int Count { get; } + public bool IsReadOnly { get; } + public int IndexOf(T item) + { + throw new NotImplementedException(); + } + + public void Insert(int index, T item) + { + throw new NotImplementedException(); + } + + public void RemoveAt(int index) + { + throw new NotImplementedException(); + } + + public T this[int index] + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } } #if !(NET40 || NET35 || NET20 || PORTABLE40) diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index cb37f805..53fc1fa1 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -5286,7 +5286,7 @@ Path '', line 1, position 1."); } #endif -#if !NETFX_CORE +#if !(NETFX_CORE || DNXCORE50) public class XmlNodeTestObject { public XmlDocument Document { get; set; } @@ -6104,15 +6104,15 @@ Path '', line 1, position 1."); public void PublicConstructorOverridenByJsonConstructorTest() { PublicConstructorOverridenByJsonConstructor c = JsonConvert.DeserializeObject("{Value:'value!'}"); - Assert.AreEqual("Public Paramatized", c.Constructor); + Assert.AreEqual("Public Parameterized", c.Constructor); Assert.AreEqual("value!", c.Value); } [Test] - public void MultipleParamatrizedConstructorsJsonConstructorTest() + public void MultipleParametrizedConstructorsJsonConstructorTest() { - MultipleParamatrizedConstructorsJsonConstructor c = JsonConvert.DeserializeObject("{Value:'value!', Age:1}"); - Assert.AreEqual("Public Paramatized 2", c.Constructor); + MultipleParametrizedConstructorsJsonConstructor c = JsonConvert.DeserializeObject("{Value:'value!', Age:1}"); + Assert.AreEqual("Public Parameterized 2", c.Constructor); Assert.AreEqual("value!", c.Value); Assert.AreEqual(1, c.Age); } @@ -9760,7 +9760,7 @@ Path '', line 1, position 1."); public NonPublicConstructorWithJsonConstructor(string value) { Value = value; - Constructor = "Public Paramatized"; + Constructor = "Public Parameterized"; } } @@ -9803,28 +9803,28 @@ Path '', line 1, position 1."); public PublicConstructorOverridenByJsonConstructor(string value) { Value = value; - Constructor = "Public Paramatized"; + Constructor = "Public Parameterized"; } } - public class MultipleParamatrizedConstructorsJsonConstructor + public class MultipleParametrizedConstructorsJsonConstructor { public string Value { get; private set; } public int Age { get; private set; } public string Constructor { get; private set; } - public MultipleParamatrizedConstructorsJsonConstructor(string value) + public MultipleParametrizedConstructorsJsonConstructor(string value) { Value = value; - Constructor = "Public Paramatized 1"; + Constructor = "Public Parameterized 1"; } [JsonConstructor] - public MultipleParamatrizedConstructorsJsonConstructor(string value, int age) + public MultipleParametrizedConstructorsJsonConstructor(string value, int age) { Value = value; Age = age; - Constructor = "Public Paramatized 2"; + Constructor = "Public Parameterized 2"; } } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs index f413e85f..08c3c6b8 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs @@ -528,6 +528,72 @@ namespace Newtonsoft.Json.Tests.Serialization JObject o = (JObject)actual.Payload; Assert.AreEqual("System.Byte[], mscorlib", (string)o["$type"]); Assert.AreEqual("AAECAwQFBgcICQ==", (string)o["$value"]); + Assert.AreEqual(null, o.Parent); + } + + [Test] + public void ReadAhead_JObject_NoParent() + { + ItemWithUntypedPayload actual = JsonConvert.DeserializeObject(@"{ + ""Payload"": {} +}", + new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead + }); + + JObject o = (JObject)actual.Payload; + Assert.AreEqual(null, o.Parent); + } + + public class ItemWithJTokens + { + public JValue Payload1 { get; set; } + public JObject Payload2 { get; set; } + public JArray Payload3 { get; set; } + } + + [Test] + public void ReadAhead_TypedJValue_NoParent() + { + ItemWithJTokens actual = (ItemWithJTokens)JsonConvert.DeserializeObject(@"{ + ""Payload1"": 1, + ""Payload2"": {'prop1':1,'prop2':[2]}, + ""Payload3"": [1], + ""$type"": ""Newtonsoft.Json.Tests.Serialization.MetadataPropertyHandlingTests+ItemWithJTokens, Newtonsoft.Json.Tests"" +}", + new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead, + TypeNameHandling = TypeNameHandling.All + }); + + Assert.AreEqual(JTokenType.Integer, actual.Payload1.Type); + Assert.AreEqual(1, (int)actual.Payload1); + Assert.AreEqual(null, actual.Payload1.Parent); + + Assert.AreEqual(JTokenType.Object, actual.Payload2.Type); + Assert.AreEqual(1, (int)actual.Payload2["prop1"]); + Assert.AreEqual(2, (int)actual.Payload2["prop2"][0]); + Assert.AreEqual(null, actual.Payload2.Parent); + + Assert.AreEqual(1, (int)actual.Payload3[0]); + Assert.AreEqual(null, actual.Payload3.Parent); + } + + [Test] + public void ReadAhead_JArray_NoParent() + { + ItemWithUntypedPayload actual = JsonConvert.DeserializeObject(@"{ + ""Payload"": [1] +}", + new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead + }); + + JArray o = (JArray)actual.Payload; + Assert.AreEqual(null, o.Parent); } public class ItemWithUntypedPayload diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs index dad49a58..d16dc63f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs @@ -71,7 +71,12 @@ namespace Newtonsoft.Json.Tests.Serialization [Test] public void GetAttributes_Property() { - PropertyInfo property = typeof(ReflectionTestObject).GetProperty("TestProperty"); + PropertyInfo property; +#if DNXCORE50 + property = Newtonsoft.Json.Utilities.TypeExtensions.GetProperty(typeof(ReflectionTestObject), "TestProperty"); +#else + property = typeof(ReflectionTestObject).GetProperty("TestProperty"); +#endif ReflectionAttributeProvider provider = new ReflectionAttributeProvider(property); @@ -85,7 +90,12 @@ namespace Newtonsoft.Json.Tests.Serialization [Test] public void GetAttributes_Field() { - FieldInfo field = (FieldInfo)typeof(ReflectionTestObject).GetField("TestField"); + FieldInfo field; +#if DNXCORE50 + field = (FieldInfo)Newtonsoft.Json.Utilities.TypeExtensions.GetField(typeof(ReflectionTestObject), "TestField"); +#else + field = typeof(ReflectionTestObject).GetField("TestField"); +#endif ReflectionAttributeProvider provider = new ReflectionAttributeProvider(field); diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs index 1844246f..a3099970 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs @@ -74,11 +74,14 @@ namespace Newtonsoft.Json.Tests.Serialization var possibleMsgs = new[] { "[1] - Error message for member 1 = An item with the same key has already been added.", - "[1] - Error message for member 1 = An element with the same key already exists in the dictionary." // mono + "[1] - Error message for member 1 = An element with the same key already exists in the dictionary.", // mono + "[1] - Error message for member 1 = An item with the same key has already been added. Key: Jim" // netcore }; VersionKeyedCollection c = JsonConvert.DeserializeObject(json); Assert.AreEqual(1, c.Count); Assert.AreEqual(1, c.Messages.Count); + + Console.WriteLine(c.Messages[0]); Assert.IsTrue(possibleMsgs.Any(m => m == c.Messages[0]), "Expected One of: " + Environment.NewLine + string.Join(Environment.NewLine, possibleMsgs) + Environment.NewLine + "Was: " + Environment.NewLine + c.Messages[0]); } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs index 86d2a62f..e931c634 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs @@ -733,7 +733,7 @@ Newtonsoft.Json Error: 0 : Error! } [Test] - public void PublicParametizedConstructorWithPropertyNameConflictWithAttribute() + public void PublicParameterizedConstructorWithPropertyNameConflictWithAttribute() { InMemoryTraceWriter traceWriter = new InMemoryTraceWriter { @@ -742,7 +742,7 @@ Newtonsoft.Json Error: 0 : Error! string json = @"{name:""1""}"; - PublicParametizedConstructorWithPropertyNameConflictWithAttribute c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + PublicParameterizedConstructorWithPropertyNameConflictWithAttribute c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TraceWriter = traceWriter }); @@ -750,7 +750,7 @@ Newtonsoft.Json Error: 0 : Error! Assert.IsNotNull(c); Assert.AreEqual(1, c.Name); - Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.PublicParametizedConstructorWithPropertyNameConflictWithAttribute using creator with parameters: name. Path 'name', line 1, position 6.", traceWriter.TraceRecords[0].Message); + Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.PublicParameterizedConstructorWithPropertyNameConflictWithAttribute using creator with parameters: name. Path 'name', line 1, position 6.", traceWriter.TraceRecords[0].Message); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs index 6e748b1c..915e837f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs @@ -41,7 +41,7 @@ using Assert = Newtonsoft.Json.Tests.XUnitAssert; #else using NUnit.Framework; #endif -#if !(NETFX_CORE || NET20 || NET35) +#if !(NETFX_CORE || NET20 || NET35 || DNXCORE50) using System.Runtime.Serialization.Json; #endif using Newtonsoft.Json.Serialization; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs index 9333c511..23ef39cd 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs @@ -66,7 +66,11 @@ namespace Newtonsoft.Json.Tests.TestObjects public override bool CanConvert(Type objectType) { +#if DNXCORE50 + return Newtonsoft.Json.Utilities.TypeExtensions.IsAssignableFrom(typeof(IList), objectType); +#else return typeof(IList).IsAssignableFrom(objectType); +#endif } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParametizedConstructorTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParameterizedConstructorTestClass.cs similarity index 85% rename from Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParametizedConstructorTestClass.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParameterizedConstructorTestClass.cs index d63748fc..56dabb52 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParametizedConstructorTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PrivateConstructorWithPublicParameterizedConstructorTestClass.cs @@ -27,17 +27,17 @@ using System; namespace Newtonsoft.Json.Tests.TestObjects { - public class PrivateConstructorWithPublicParametizedConstructorTestClass + public class PrivateConstructorWithPublicParameterizedConstructorTestClass { public string Name { get; set; } public int Age { get; set; } - private PrivateConstructorWithPublicParametizedConstructorTestClass() + private PrivateConstructorWithPublicParameterizedConstructorTestClass() { Age = 1; } - public PrivateConstructorWithPublicParametizedConstructorTestClass(string dummy) + public PrivateConstructorWithPublicParameterizedConstructorTestClass(string dummy) { throw new Exception("Should never get here."); } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorRequiringConverterTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorRequiringConverterTestClass.cs similarity index 81% rename from Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorRequiringConverterTestClass.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorRequiringConverterTestClass.cs index 31467032..e1e3d3eb 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorRequiringConverterTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorRequiringConverterTestClass.cs @@ -62,11 +62,11 @@ namespace Newtonsoft.Json.Tests.TestObjects } } - public class PublicParametizedConstructorRequiringConverterTestClass + public class PublicParameterizedConstructorRequiringConverterTestClass { private readonly NameContainer _nameContainer; - public PublicParametizedConstructorRequiringConverterTestClass(NameContainer nameParameter) + public PublicParameterizedConstructorRequiringConverterTestClass(NameContainer nameParameter) { _nameContainer = nameParameter; } @@ -77,11 +77,11 @@ namespace Newtonsoft.Json.Tests.TestObjects } } - public class PublicParametizedConstructorRequiringConverterWithParameterAttributeTestClass + public class PublicParameterizedConstructorRequiringConverterWithParameterAttributeTestClass { private readonly NameContainer _nameContainer; - public PublicParametizedConstructorRequiringConverterWithParameterAttributeTestClass([JsonConverter(typeof(NameContainerConverter))] NameContainer nameParameter) + public PublicParameterizedConstructorRequiringConverterWithParameterAttributeTestClass([JsonConverter(typeof(NameContainerConverter))] NameContainer nameParameter) { _nameContainer = nameParameter; } @@ -92,11 +92,11 @@ namespace Newtonsoft.Json.Tests.TestObjects } } - public class PublicParametizedConstructorRequiringConverterWithPropertyAttributeTestClass + public class PublicParameterizedConstructorRequiringConverterWithPropertyAttributeTestClass { private readonly NameContainer _nameContainer; - public PublicParametizedConstructorRequiringConverterWithPropertyAttributeTestClass(NameContainer name) + public PublicParameterizedConstructorRequiringConverterWithPropertyAttributeTestClass(NameContainer name) { _nameContainer = name; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorTestClass.cs similarity index 91% rename from Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorTestClass.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorTestClass.cs index 24dd7871..c0dafbfa 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorTestClass.cs @@ -25,11 +25,11 @@ namespace Newtonsoft.Json.Tests.TestObjects { - public class PublicParametizedConstructorTestClass + public class PublicParameterizedConstructorTestClass { private readonly string _name; - public PublicParametizedConstructorTestClass(string name) + public PublicParameterizedConstructorTestClass(string name) { _name = name; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithNonPropertyParameterTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithNonPropertyParameterTestClass.cs similarity index 88% rename from Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithNonPropertyParameterTestClass.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithNonPropertyParameterTestClass.cs index 6fb286f6..66e8caff 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithNonPropertyParameterTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithNonPropertyParameterTestClass.cs @@ -25,11 +25,11 @@ namespace Newtonsoft.Json.Tests.TestObjects { - public class PublicParametizedConstructorWithNonPropertyParameterTestClass + public class PublicParameterizedConstructorWithNonPropertyParameterTestClass { private readonly string _name; - public PublicParametizedConstructorWithNonPropertyParameterTestClass(string nameParameter) + public PublicParameterizedConstructorWithNonPropertyParameterTestClass(string nameParameter) { _name = nameParameter; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithPropertyNameConflict.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithPropertyNameConflict.cs similarity index 81% rename from Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithPropertyNameConflict.cs rename to Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithPropertyNameConflict.cs index 14b8c5cd..5bee1a6c 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PublicParametizedConstructorWithPropertyNameConflict.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PublicParameterizedConstructorWithPropertyNameConflict.cs @@ -27,11 +27,11 @@ using System; namespace Newtonsoft.Json.Tests.TestObjects { - public class PublicParametizedConstructorWithPropertyNameConflict + public class PublicParameterizedConstructorWithPropertyNameConflict { private readonly int _value; - public PublicParametizedConstructorWithPropertyNameConflict(string name) + public PublicParameterizedConstructorWithPropertyNameConflict(string name) { _value = Convert.ToInt32(name); } @@ -42,11 +42,11 @@ namespace Newtonsoft.Json.Tests.TestObjects } } - public class PublicParametizedConstructorWithPropertyNameConflictWithAttribute + public class PublicParameterizedConstructorWithPropertyNameConflictWithAttribute { private readonly int _value; - public PublicParametizedConstructorWithPropertyNameConflictWithAttribute([JsonProperty("name")] string nameParameter) + public PublicParameterizedConstructorWithPropertyNameConflictWithAttribute([JsonProperty("name")] string nameParameter) { _value = Convert.ToInt32(nameParameter); } diff --git a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs index a4a93c52..3fc261d0 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs @@ -175,6 +175,24 @@ namespace Newtonsoft.Json.Tests.Utilities JsonSerializerTest.DictionaryKey key = (JsonSerializerTest.DictionaryKey)result; Assert.AreEqual("First!", key.Value); } + + [Test] + public void CreatePropertyGetter() + { + PropertyInfo namePropertyInfo = typeof(Person).GetProperty(nameof(Person.Name)); + + Assert.IsNotNull(namePropertyInfo); + + var call = DynamicReflectionDelegateFactory.Instance.CreateGet(namePropertyInfo); + + Person p = new Person(); + p.Name = "Name!"; + + object result = call(p); + Assert.IsNotNull(result); + + Assert.AreEqual("Name!", (string)result); + } } } diff --git a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs index ea5dd389..893776b1 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs @@ -57,6 +57,7 @@ namespace Newtonsoft.Json.Tests.Utilities Assert.AreEqual(" IPhone", StringUtils.ToCamelCase(" IPhone")); Assert.AreEqual("isCIA", StringUtils.ToCamelCase("IsCIA")); Assert.AreEqual("vmQ", StringUtils.ToCamelCase("VmQ")); + Assert.AreEqual("xml2Json", StringUtils.ToCamelCase("Xml2Json")); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/project.json b/Src/Newtonsoft.Json.Tests/project.json index 5c105e65..4c6f7b29 100644 --- a/Src/Newtonsoft.Json.Tests/project.json +++ b/Src/Newtonsoft.Json.Tests/project.json @@ -1,17 +1,13 @@ { "version": "1.0.0-*", - "exclude": [ - ], "dependencies": { "Newtonsoft.Json": { "target": "project" } }, - "commands": { - "test": "xunit.runner.dnx -parallel none" - }, + "testRunner": "xunit", "frameworks": { - "net45": { + /*"net45": { "frameworkAssemblies": { "System.Collections": "", "System.ComponentModel.DataAnnotations": "", @@ -38,7 +34,6 @@ }, "net40": { "frameworkAssemblies": { - "System.Collections": "", "System.ComponentModel.DataAnnotations": "", "System.Data": "", "System.Data.DataSetExtensions": "", @@ -46,7 +41,6 @@ "System.Data.Linq": "", "System.Drawing": "", "System.Numerics": "", - "System.Runtime": "", "System.Runtime.Serialization": "", "System.Web": "", "System.Web.Extensions": "", @@ -87,40 +81,27 @@ "dependencies": { "NUnit": "2.6.4" } - }, - "dnxcore50": { + },*/ + "netcoreapp1.0": { + "buildOptions": { + "define": [ "NETSTANDARD10", "DNXCORE50", "PORTABLE" ] + }, "dependencies": { - "Microsoft.CSharp": "4.0.0", - "System.Collections": "4.0.10", - "System.Collections.Immutable": "1.1.37", - "System.ComponentModel.TypeConverter": "4.0.0", - "System.Diagnostics.Debug": "4.0.10", - "System.Dynamic.Runtime": "4.0.10", - "System.Globalization": "4.0.10", - "System.IO": "4.0.10", - "System.Linq": "4.0.0", - "System.Linq.Expressions": "4.0.10", - "System.Reflection.Emit.ILGeneration": "4.0.0", - "System.Reflection.Extensions": "4.0.0", - "System.Reflection.TypeExtensions": "4.0.0", - "System.Runtime": "4.0.20", - "System.Runtime.Extensions": "4.0.10", - "System.Runtime.Numerics": "4.0.0", - "System.Runtime.Serialization.Json": "4.0.0", - "System.Runtime.Serialization.Primitives": "4.0.10", - "System.Runtime.Serialization.Xml": "4.0.10", - "System.Text.Encoding": "4.0.10", - "System.Text.Encoding.CodePages": "4.0.0", - "System.Text.Encoding.Extensions": "4.0.10", - "System.Text.RegularExpressions": "4.0.10", - "System.Threading": "4.0.10", - "System.Xml.ReaderWriter": "4.0.10", - "System.Xml.XDocument": "4.0.10", - "System.Xml.XmlDocument": "4.0.0", - "System.Xml.XmlSerializer": "4.0.10", - "xunit": "2.1.0-*", - "xunit.runner.dnx": "2.1.0-rc1-build204" - } + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-3002702" + }, + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027", + "System.Xml.XmlSerializer": "4.0.11-rc2-24027", + "System.Runtime.Serialization.Json": "4.0.2-rc2-24027", + "System.Runtime.Serialization.Xml": "4.1.1-rc2-24027", + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-rc2-build10015" + }, + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index 0ea895a6..0c8559ed 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -178,7 +178,7 @@ namespace Newtonsoft.Json.Bson /// Reads the next JSON token from the stream. /// /// - /// true if the next token was read successfully; false if there are no more tokens to read. + /// true if the next token was read successfully; false if there are no more tokens to read. /// public override bool Read() { diff --git a/Src/Newtonsoft.Json/ConstructorHandling.cs b/Src/Newtonsoft.Json/ConstructorHandling.cs index e403f1e4..2455d61d 100644 --- a/Src/Newtonsoft.Json/ConstructorHandling.cs +++ b/Src/Newtonsoft.Json/ConstructorHandling.cs @@ -31,12 +31,12 @@ namespace Newtonsoft.Json public enum ConstructorHandling { /// - /// First attempt to use the public default constructor, then fall back to single paramatized constructor, then the non-public default constructor. + /// First attempt to use the public default constructor, then fall back to single parameterized constructor, then the non-public default constructor. /// Default = 0, /// - /// Json.NET will use a non-public default constructor before falling back to a paramatized constructor. + /// Json.NET will use a non-public default constructor before falling back to a parameterized constructor. /// AllowNonPublicDefaultConstructor = 1 } diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 051f6768..d4dd7903 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -37,16 +37,9 @@ using Newtonsoft.Json.Serialization; using System.Xml.Linq; #endif using Newtonsoft.Json.Utilities; -#if NET20 -using Newtonsoft.Json.Utilities.LinqBridge; -#else -using System.Linq; - -#endif namespace Newtonsoft.Json.Converters { - #region XmlNodeWrappers #if !DOTNET && !PORTABLE && !PORTABLE40 internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument @@ -234,7 +227,8 @@ namespace Newtonsoft.Json.Converters internal class XmlNodeWrapper : IXmlNode { private readonly XmlNode _node; - private IList _childNodes; + private List _childNodes; + private List _attributes; public XmlNodeWrapper(XmlNode node) { @@ -256,7 +250,7 @@ namespace Newtonsoft.Json.Converters get { return _node.LocalName; } } - public IList ChildNodes + public List ChildNodes { get { @@ -264,7 +258,11 @@ namespace Newtonsoft.Json.Converters // cache results to prevent multiple reads which kills perf in large documents if (_childNodes == null) { - _childNodes = _node.ChildNodes.Cast().Select(WrapNode).ToList(); + _childNodes = new List(_node.ChildNodes.Count); + foreach (XmlNode childNode in _node.ChildNodes) + { + _childNodes.Add(WrapNode(childNode)); + } } return _childNodes; @@ -286,7 +284,7 @@ namespace Newtonsoft.Json.Converters } } - public IList Attributes + public List Attributes { get { @@ -295,7 +293,18 @@ namespace Newtonsoft.Json.Converters return null; } - return _node.Attributes.Cast().Select(WrapNode).ToList(); + // attributes is read multiple times + // cache results to prevent multiple reads which kills perf in large documents + if (_attributes == null) + { + _attributes = new List(_node.Attributes.Count); + foreach (XmlAttribute attribute in _node.Attributes) + { + _attributes.Add(WrapNode(attribute)); + } + } + + return _attributes; } } @@ -327,6 +336,7 @@ namespace Newtonsoft.Json.Converters XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper)newChild; _node.AppendChild(xmlNodeWrapper._node); _childNodes = null; + _attributes = null; return newChild; } @@ -384,8 +394,8 @@ namespace Newtonsoft.Json.Converters { XmlNodeType NodeType { get; } string LocalName { get; } - IList ChildNodes { get; } - IList Attributes { get; } + List ChildNodes { get; } + List Attributes { get; } IXmlNode ParentNode { get; } string Value { get; set; } IXmlNode AppendChild(IXmlNode newChild); @@ -477,11 +487,11 @@ namespace Newtonsoft.Json.Converters { } - public override IList ChildNodes + public override List ChildNodes { get { - IList childNodes = base.ChildNodes; + List childNodes = base.ChildNodes; if (Document.Declaration != null && childNodes[0].NodeType != XmlNodeType.XmlDeclaration) { @@ -672,7 +682,7 @@ namespace Newtonsoft.Json.Converters internal class XContainerWrapper : XObjectWrapper { - private IList _childNodes; + private List _childNodes; private XContainer Container { @@ -684,7 +694,7 @@ namespace Newtonsoft.Json.Converters { } - public override IList ChildNodes + public override List ChildNodes { get { @@ -692,7 +702,11 @@ namespace Newtonsoft.Json.Converters // cache results to prevent multiple reads which kills perf in large documents if (_childNodes == null) { - _childNodes = Container.Nodes().Select(WrapNode).ToList(); + _childNodes = new List(); + foreach (XNode node in Container.Nodes()) + { + _childNodes.Add(WrapNode(node)); + } } return _childNodes; @@ -763,6 +777,7 @@ namespace Newtonsoft.Json.Converters internal class XObjectWrapper : IXmlNode { + private static readonly List EmptyChildNodes = new List(); private readonly XObject _xmlObject; public XObjectWrapper(XObject xmlObject) @@ -785,12 +800,12 @@ namespace Newtonsoft.Json.Converters get { return null; } } - public virtual IList ChildNodes + public virtual List ChildNodes { - get { return new List(); } + get { return EmptyChildNodes; } } - public virtual IList Attributes + public virtual List Attributes { get { return null; } } @@ -861,6 +876,8 @@ namespace Newtonsoft.Json.Converters internal class XElementWrapper : XContainerWrapper, IXmlElement { + private List _attributes; + private XElement Element { get { return (XElement)WrappedNode; } @@ -875,11 +892,56 @@ namespace Newtonsoft.Json.Converters { XObjectWrapper wrapper = (XObjectWrapper)attribute; Element.Add(wrapper.WrappedNode); + _attributes = null; } - public override IList Attributes + public override List Attributes { - get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast().ToList(); } + get + { + // attributes is read multiple times + // cache results to prevent multiple reads which kills perf in large documents + if (_attributes == null) + { + _attributes = new List(); + foreach (XAttribute attribute in Element.Attributes()) + { + _attributes.Add(new XAttributeWrapper(attribute)); + } + + // ensure elements created with a namespace but no namespace attribute are converted correctly + // e.g. new XElement("{http://example.com}MyElement"); + string namespaceUri = NamespaceUri; + if (!string.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri) + { + if (string.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri))) + { + bool namespaceDeclared = false; + foreach (IXmlNode attribute in _attributes) + { + if (attribute.LocalName == "xmlns" && string.IsNullOrEmpty(attribute.NamespaceUri) && attribute.Value == namespaceUri) + { + namespaceDeclared = true; + } + } + + if (!namespaceDeclared) + { + _attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri))); + } + } + } + } + + return _attributes; + } + } + + public override IXmlNode AppendChild(IXmlNode newChild) + { + IXmlNode result = base.AppendChild(newChild); + _attributes = null; + return result; } public override string Value @@ -1085,11 +1147,18 @@ namespace Newtonsoft.Json.Converters private bool IsArray(IXmlNode node) { - IXmlNode jsonArrayAttribute = (node.Attributes != null) - ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceUri == JsonNamespaceUri) - : null; + if (node.Attributes != null) + { + foreach (IXmlNode attribute in node.Attributes) + { + if (attribute.LocalName == "Array" && attribute.NamespaceUri == JsonNamespaceUri) + { + return XmlConvert.ToBoolean(attribute.Value); + } + } + } - return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value)); + return false; } private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName) @@ -1162,7 +1231,7 @@ namespace Newtonsoft.Json.Converters SerializeGroupedNodes(writer, node, manager, writePropertyName); break; case XmlNodeType.Element: - if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName) && node.ChildNodes.Count > 0) + if (IsArray(node) && AllSameName(node) && node.ChildNodes.Count > 0) { SerializeGroupedNodes(writer, node, manager, false); } @@ -1188,7 +1257,7 @@ namespace Newtonsoft.Json.Converters writer.WritePropertyName(GetPropertyName(node, manager)); } - if (!ValueAttributes(node.Attributes).Any() && node.ChildNodes.Count == 1 + if (!ValueAttributes(node.Attributes) && node.ChildNodes.Count == 1 && node.ChildNodes[0].NodeType == XmlNodeType.Text) { // write elements with a single text child as a name value pair @@ -1312,6 +1381,18 @@ namespace Newtonsoft.Json.Converters throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType); } } + + private static bool AllSameName(IXmlNode node) + { + foreach (IXmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName != node.LocalName) + { + return false; + } + } + return true; + } #endregion #region Reading @@ -1459,26 +1540,30 @@ namespace Newtonsoft.Json.Converters string attributePrefix = MiscellaneousUtils.GetPrefix(attributeName); AddAttribute(reader, document, currentNode, attributeName, manager, attributePrefix); + return; } - else if (propertyName.StartsWith('$')) + + if (propertyName.StartsWith('$')) { - if (propertyName == JsonTypeReflector.ArrayValuesPropertyName) + switch (propertyName) { - propertyName = propertyName.Substring(1); - elementPrefix = manager.LookupPrefix(JsonNamespaceUri); - CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); - } - else - { - string attributeName = propertyName.Substring(1); - string attributePrefix = manager.LookupPrefix(JsonNamespaceUri); - AddAttribute(reader, document, currentNode, attributeName, manager, attributePrefix); + case JsonTypeReflector.ArrayValuesPropertyName: + propertyName = propertyName.Substring(1); + elementPrefix = manager.LookupPrefix(JsonNamespaceUri); + CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); + return; + case JsonTypeReflector.IdPropertyName: + case JsonTypeReflector.RefPropertyName: + case JsonTypeReflector.TypePropertyName: + case JsonTypeReflector.ValuePropertyName: + string attributeName = propertyName.Substring(1); + string attributePrefix = manager.LookupPrefix(JsonNamespaceUri); + AddAttribute(reader, document, currentNode, attributeName, manager, attributePrefix); + return; } } - else - { - CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); - } + + CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); } private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string elementPrefix, Dictionary attributeNameValues) @@ -1624,8 +1709,15 @@ namespace Newtonsoft.Json.Converters if (count == 1 && WriteArrayAttribute) { - IXmlElement arrayElement = nestedArrayElement.ChildNodes.OfType().Single(n => n.LocalName == propertyName); - AddJsonArrayAttribute(arrayElement, document); + foreach (IXmlNode childNode in nestedArrayElement.ChildNodes) + { + IXmlElement element = childNode as IXmlElement; + if (element != null && element.LocalName == propertyName) + { + AddJsonArrayAttribute(element, document); + break; + } + } } } @@ -1688,40 +1780,52 @@ namespace Newtonsoft.Json.Converters } break; case '$': - // check that JsonNamespaceUri is in scope - // if it isn't then add it to document and namespace manager - string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); - if (jsonPrefix == null) + switch (attributeName) { - // ensure that the prefix used is free - int? i = null; - while (manager.LookupNamespace("json" + i) != null) - { - i = i.GetValueOrDefault() + 1; - } - jsonPrefix = "json" + i; + case JsonTypeReflector.ArrayValuesPropertyName: + case JsonTypeReflector.IdPropertyName: + case JsonTypeReflector.RefPropertyName: + case JsonTypeReflector.TypePropertyName: + case JsonTypeReflector.ValuePropertyName: + // check that JsonNamespaceUri is in scope + // if it isn't then add it to document and namespace manager + string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); + if (jsonPrefix == null) + { + // ensure that the prefix used is free + int? i = null; + while (manager.LookupNamespace("json" + i) != null) + { + i = i.GetValueOrDefault() + 1; + } + jsonPrefix = "json" + i; - attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri); - manager.AddNamespace(jsonPrefix, JsonNamespaceUri); + attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri); + manager.AddNamespace(jsonPrefix, JsonNamespaceUri); + } + + // special case $values, it will have a non-primitive value + if (attributeName == JsonTypeReflector.ArrayValuesPropertyName) + { + finishedAttributes = true; + break; + } + + attributeName = attributeName.Substring(1); + reader.Read(); + + if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) + { + throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType); + } + + attributeValue = (reader.Value != null) ? reader.Value.ToString() : null; + attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue); + break; + default: + finishedAttributes = true; + break; } - - // special case $values, it will have a non-primitive value - if (attributeName == JsonTypeReflector.ArrayValuesPropertyName) - { - finishedAttributes = true; - break; - } - - attributeName = attributeName.Substring(1); - reader.Read(); - - if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) - { - throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType); - } - - attributeValue = (reader.Value != null) ? reader.Value.ToString() : null; - attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue); break; default: finishedAttributes = true; @@ -1858,8 +1962,15 @@ namespace Newtonsoft.Json.Converters if (count == 1 && WriteArrayAttribute) { - IXmlElement arrayElement = currentNode.ChildNodes.OfType().Single(n => n.LocalName == propertyName); - AddJsonArrayAttribute(arrayElement, document); + foreach (IXmlNode childNode in currentNode.ChildNodes) + { + IXmlElement element = childNode as IXmlElement; + if (element != null && element.LocalName == propertyName) + { + AddJsonArrayAttribute(element, document); + break; + } + } } } else @@ -1893,7 +2004,7 @@ namespace Newtonsoft.Json.Converters /// /// Attribute name to test. /// The attribute name prefix if it has one, otherwise an empty string. - /// True if attribute name is for a namespace attribute, otherwise false. + /// true if attribute name is for a namespace attribute, otherwise false. private bool IsNamespaceAttribute(string attributeName, out string prefix) { if (attributeName.StartsWith("xmlns", StringComparison.Ordinal)) @@ -1913,9 +2024,17 @@ namespace Newtonsoft.Json.Converters return false; } - private IEnumerable ValueAttributes(IEnumerable c) + private bool ValueAttributes(List c) { - return c.Where(a => a.NamespaceUri != JsonNamespaceUri); + foreach (IXmlNode xmlNode in c) + { + if (xmlNode.NamespaceUri != JsonNamespaceUri) + { + return true; + } + } + + return false; } #endregion diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index ce71c23e..4df922cb 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -407,7 +407,7 @@ namespace Newtonsoft.Json /// /// Reads the next JSON token from the stream. /// - /// true if the next token was read successfully; false if there are no more tokens to read. + /// true if the next token was read successfully; false if there are no more tokens to read. public abstract bool Read(); /// @@ -622,12 +622,24 @@ namespace Newtonsoft.Json case JsonToken.Float: if (!(Value is double)) { - SetToken(JsonToken.Float, Convert.ToDouble(Value, CultureInfo.InvariantCulture), false); + double d; +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) + if (Value is BigInteger) + { + d = (double)(BigInteger)Value; + } + else +#endif + { + d = Convert.ToDouble(Value, CultureInfo.InvariantCulture); + } + + SetToken(JsonToken.Float, d, false); } - return (double) Value; + return (double)Value; case JsonToken.String: - return ReadDoubleString((string) Value); + return ReadDoubleString((string)Value); } throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 96a3ee83..cf2ca06b 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -362,7 +362,7 @@ namespace Newtonsoft.Json /// Reads the next JSON token from the stream. /// /// - /// true if the next token was read successfully; false if there are no more tokens to read. + /// true if the next token was read successfully; false if there are no more tokens to read. /// public override bool Read() { @@ -598,6 +598,15 @@ namespace Newtonsoft.Json throw new ArgumentOutOfRangeException(nameof(readType)); } case '-': + if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') + { + return ParseNumberNegativeInfinity(readType); + } + else + { + ParseNumber(readType); + return Value; + } case '.': case '0': case '1': @@ -614,10 +623,8 @@ namespace Newtonsoft.Json _charPos++; throw CreateUnexpectedCharacterException(currentChar); } - ParseNumber(ReadType.Read); - string s = ((IFormattable)Value).ToString(null, CultureInfo.InvariantCulture); - SetToken(JsonToken.String, s); - return s; + ParseNumber(ReadType.ReadAsString); + return Value; case 't': case 'f': if (readType != ReadType.ReadAsString) @@ -632,6 +639,10 @@ namespace Newtonsoft.Json } SetToken(JsonToken.String, expected); return expected; + case 'I': + return ParseNumberPositiveInfinity(readType); + case 'N': + return ParseNumberNaN(readType); case 'n': HandleNull(); return null; @@ -860,7 +871,20 @@ namespace Newtonsoft.Json case 'n': HandleNull(); return null; + case 'N': + return ParseNumberNaN(readType); + case 'I': + return ParseNumberPositiveInfinity(readType); case '-': + if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') + { + return ParseNumberNegativeInfinity(readType); + } + else + { + ParseNumber(readType); + return Value; + } case '.': case '0': case '1': @@ -1569,15 +1593,15 @@ namespace Newtonsoft.Json } return true; case 'N': - ParseNumberNaN(); + ParseNumberNaN(ReadType.Read); return true; case 'I': - ParseNumberPositiveInfinity(); + ParseNumberPositiveInfinity(ReadType.Read); return true; case '-': if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') { - ParseNumberNegativeInfinity(); + ParseNumberNegativeInfinity(ReadType.Read); } else { @@ -1807,7 +1831,42 @@ namespace Newtonsoft.Json bool singleDigit = (char.IsDigit(firstChar) && _stringReference.Length == 1); bool nonBase10 = (firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E'); - if (readType == ReadType.ReadAsInt32) + if (readType == ReadType.ReadAsString) + { + string number = _stringReference.ToString(); + + // validate that the string is a valid number + if (nonBase10) + { + try + { + if (number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + Convert.ToInt64(number, 16); + } + else + { + Convert.ToInt64(number, 8); + } + } + catch (Exception ex) + { + throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex); + } + } + else + { + double value; + if (!double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) + { + throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); + } + } + + numberType = JsonToken.String; + numberValue = number; + } + else if (readType == ReadType.ReadAsInt32) { if (singleDigit) { @@ -2260,55 +2319,79 @@ namespace Newtonsoft.Json } } - private void ParseNumberNegativeInfinity() + private object ParseNumberNegativeInfinity(ReadType readType) { if (MatchValueWithTrailingSeparator(JsonConvert.NegativeInfinity)) { - if (_floatParseHandling == FloatParseHandling.Decimal) + switch (readType) { - throw new JsonReaderException("Cannot read -Infinity as a decimal."); + case ReadType.Read: + case ReadType.ReadAsDouble: + if (_floatParseHandling == FloatParseHandling.Double) + { + SetToken(JsonToken.Float, double.NegativeInfinity); + return double.NegativeInfinity; + } + break; + case ReadType.ReadAsString: + SetToken(JsonToken.String, JsonConvert.NegativeInfinity); + return JsonConvert.NegativeInfinity; } - SetToken(JsonToken.Float, double.NegativeInfinity); - } - else - { - throw JsonReaderException.Create(this, "Error parsing negative infinity value."); + throw JsonReaderException.Create(this, "Cannot read -Infinity value."); } + + throw JsonReaderException.Create(this, "Error parsing -Infinity value."); } - private void ParseNumberPositiveInfinity() + private object ParseNumberPositiveInfinity(ReadType readType) { if (MatchValueWithTrailingSeparator(JsonConvert.PositiveInfinity)) { - if (_floatParseHandling == FloatParseHandling.Decimal) + switch (readType) { - throw new JsonReaderException("Cannot read Infinity as a decimal."); + case ReadType.Read: + case ReadType.ReadAsDouble: + if (_floatParseHandling == FloatParseHandling.Double) + { + SetToken(JsonToken.Float, double.PositiveInfinity); + return double.PositiveInfinity; + } + break; + case ReadType.ReadAsString: + SetToken(JsonToken.String, JsonConvert.PositiveInfinity); + return JsonConvert.PositiveInfinity; } - SetToken(JsonToken.Float, double.PositiveInfinity); - } - else - { - throw JsonReaderException.Create(this, "Error parsing positive infinity value."); + throw JsonReaderException.Create(this, "Cannot read Infinity value."); } + + throw JsonReaderException.Create(this, "Error parsing Infinity value."); } - private void ParseNumberNaN() + private object ParseNumberNaN(ReadType readType) { if (MatchValueWithTrailingSeparator(JsonConvert.NaN)) { - if (_floatParseHandling == FloatParseHandling.Decimal) + switch (readType) { - throw new JsonReaderException("Cannot read NaN as a decimal."); + case ReadType.Read: + case ReadType.ReadAsDouble: + if (_floatParseHandling == FloatParseHandling.Double) + { + SetToken(JsonToken.Float, double.NaN); + return double.NaN; + } + break; + case ReadType.ReadAsString: + SetToken(JsonToken.String, JsonConvert.NaN); + return JsonConvert.NaN; } - SetToken(JsonToken.Float, double.NaN); - } - else - { - throw JsonReaderException.Create(this, "Error parsing NaN value."); + throw JsonReaderException.Create(this, "Cannot read NaN value."); } + + throw JsonReaderException.Create(this, "Error parsing NaN value."); } /// diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs index 260791b8..6e5d75a1 100644 --- a/Src/Newtonsoft.Json/JsonValidatingReader.cs +++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs @@ -495,7 +495,7 @@ namespace Newtonsoft.Json /// Reads the next JSON token from the stream. /// /// - /// true if the next token was read successfully; false if there are no more tokens to read. + /// true if the next token was read successfully; false if there are no more tokens to read. /// public override bool Read() { diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 293b1536..40fa2bce 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -626,7 +626,7 @@ namespace Newtonsoft.Json WriteToken(token, null); } - internal void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments) + internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments) { int initialDepth; @@ -643,11 +643,6 @@ namespace Newtonsoft.Json initialDepth = reader.Depth; } - WriteToken(reader, initialDepth, writeChildren, writeDateConstructorAsDate, writeComments); - } - - internal void WriteToken(JsonReader reader, int initialDepth, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments) - { do { // write a JValue date when the constructor is for a date @@ -657,7 +652,7 @@ namespace Newtonsoft.Json } else { - if (reader.TokenType != JsonToken.Comment || writeComments) + if (writeComments || reader.TokenType != JsonToken.Comment) { WriteToken(reader.TokenType, reader.Value); } diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index 5ca9a165..ad73e028 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -270,6 +270,11 @@ namespace Newtonsoft.Json.Linq set { SetItem(index, value); } } + internal override int IndexOfItem(JToken item) + { + return _values.IndexOfReference(item); + } + internal override void MergeItem(object content, JsonMergeSettings settings) { IEnumerable a = (IsMultiContent(content) || content is JArray) diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index 0a49a93e..1411caf6 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -48,6 +48,11 @@ namespace Newtonsoft.Json.Linq get { return _values; } } + internal override int IndexOfItem(JToken item) + { + return _values.IndexOfReference(item); + } + internal override void MergeItem(object content, JsonMergeSettings settings) { JConstructor c = content as JConstructor; diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 6e902010..0ad8a5ce 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -351,30 +351,7 @@ namespace Newtonsoft.Json.Linq return item; } - private class JTokenReferenceEqualityComparer : IEqualityComparer - { - public static readonly JTokenReferenceEqualityComparer Instance = new JTokenReferenceEqualityComparer(); - - public bool Equals(JToken x, JToken y) - { - return ReferenceEquals(x, y); - } - - public int GetHashCode(JToken obj) - { - if (obj == null) - { - return 0; - } - - return obj.GetHashCode(); - } - } - - internal int IndexOfItem(JToken item) - { - return ChildrenTokens.IndexOf(item, JTokenReferenceEqualityComparer.Instance); - } + internal abstract int IndexOfItem(JToken item); internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) { @@ -698,9 +675,10 @@ namespace Newtonsoft.Json.Linq internal static JToken CreateFromContent(object content) { - if (content is JToken) + JToken token = content as JToken; + if (token != null) { - return (JToken)content; + return token; } return new JValue(content); @@ -782,7 +760,7 @@ namespace Newtonsoft.Json.Linq do { - if (parent is JProperty && ((JProperty)parent).Value != null) + if ((parent as JProperty)?.Value != null) { if (parent == this) { @@ -910,12 +888,7 @@ namespace Newtonsoft.Json.Linq PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) { ICustomTypeDescriptor d = First as ICustomTypeDescriptor; - if (d != null) - { - return d.GetProperties(); - } - - return null; + return d?.GetProperties(); } #endif @@ -981,9 +954,10 @@ namespace Newtonsoft.Json.Linq return null; } - if (value is JToken) + JToken token = value as JToken; + if (token != null) { - return (JToken)value; + return token; } throw new ArgumentException("Argument is not a JToken."); @@ -1192,7 +1166,7 @@ namespace Newtonsoft.Json.Linq } } #else - IDictionary items = new Dictionary(EqualityComparer); + Dictionary items = new Dictionary(EqualityComparer); foreach (JToken t in target) { items[t] = true; diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index 7e7d49c1..45c21403 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -128,6 +128,11 @@ namespace Newtonsoft.Json.Linq return _properties.Compare(t._properties); } + internal override int IndexOfItem(JToken item) + { + return _properties.IndexOfReference(item); + } + internal override void InsertItem(int index, JToken item, bool skipParentCheck) { // don't add comments to JObject, no name to reference comment by @@ -523,7 +528,7 @@ namespace Newtonsoft.Json.Linq /// Name of the property. /// The value. /// One of the enumeration values that specifies how the strings will be compared. - /// true if a value was successfully retrieved; otherwise, false. + /// true if a value was successfully retrieved; otherwise, false. public bool TryGetValue(string propertyName, StringComparison comparison, out JToken value) { value = GetValue(propertyName, comparison); @@ -556,7 +561,7 @@ namespace Newtonsoft.Json.Linq /// Removes the property with the specified name. /// /// Name of the property. - /// true if item was successfully removed; otherwise, false. + /// true if item was successfully removed; otherwise, false. public bool Remove(string propertyName) { JProperty property = Property(propertyName); @@ -574,7 +579,7 @@ namespace Newtonsoft.Json.Linq /// /// Name of the property. /// The value. - /// true if a value was successfully retrieved; otherwise, false. + /// true if a value was successfully retrieved; otherwise, false. public bool TryGetValue(string propertyName, out JToken value) { JProperty property = Property(propertyName); diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index a1049cf0..c68502a0 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -235,6 +235,11 @@ namespace Newtonsoft.Json.Linq throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } + internal override int IndexOfItem(JToken item) + { + return _content.IndexOf(item); + } + internal override void InsertItem(int index, JToken item, bool skipParentCheck) { // don't add comments to JProperty diff --git a/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs b/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs index 00eb8575..0b7b34eb 100644 --- a/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs +++ b/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs @@ -52,10 +52,9 @@ namespace Newtonsoft.Json.Linq /// When overridden in a derived class, returns whether resetting an object changes its value. /// /// - /// true if resetting the component changes its value; otherwise, false. + /// true if resetting the component changes its value; otherwise, false. /// - /// The component to test for reset capability. - /// + /// The component to test for reset capability. public override bool CanResetValue(object component) { return false; @@ -102,10 +101,9 @@ namespace Newtonsoft.Json.Linq /// When overridden in a derived class, determines a value indicating whether the value of this property needs to be persisted. /// /// - /// true if the property should be persisted; otherwise, false. + /// true if the property should be persisted; otherwise, false. /// - /// The component with the property to be examined for persistence. - /// + /// The component with the property to be examined for persistence. public override bool ShouldSerializeValue(object component) { return false; @@ -126,7 +124,7 @@ namespace Newtonsoft.Json.Linq /// When overridden in a derived class, gets a value indicating whether this property is read-only. /// /// - /// true if the property is read-only; otherwise, false. + /// true if the property is read-only; otherwise, false. /// public override bool IsReadOnly { diff --git a/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs b/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs index 867d741c..527fdab5 100644 --- a/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs +++ b/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Linq { @@ -35,6 +36,10 @@ namespace Newtonsoft.Json.Linq private Dictionary _dictionary; + public JPropertyKeyedCollection() : base(new List()) + { + } + private void AddKey(string key, JToken item) { EnsureDictionary(); @@ -220,6 +225,11 @@ namespace Newtonsoft.Json.Linq } } + public int IndexOfReference(JToken t) + { + return ((List)Items).IndexOfReference(t); + } + public bool Compare(JPropertyKeyedCollection other) { if (this == other) diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 7a162847..8bcbf83d 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -152,7 +152,7 @@ namespace Newtonsoft.Json.Linq /// /// The first to compare. /// The second to compare. - /// true if the tokens are equal; otherwise false. + /// true if the tokens are equal; otherwise false. public static bool DeepEquals(JToken t1, JToken t2) { return (t1 == t2 || (t1 != null && t2 != null && t1.DeepEquals(t2))); @@ -190,40 +190,32 @@ namespace Newtonsoft.Json.Linq return string.Empty; } - IList ancestors = AncestorsAndSelf().Reverse().ToList(); - List positions = new List(); - for (int i = 0; i < ancestors.Count; i++) + JToken previous = null; + for (JToken current = this; current != null; current = current.Parent) { - JToken current = ancestors[i]; - JToken next = null; - if (i + 1 < ancestors.Count) + switch (current.Type) { - next = ancestors[i + 1]; - } - else if (ancestors[i].Type == JTokenType.Property) - { - next = ancestors[i]; - } - - if (next != null) - { - switch (current.Type) - { - case JTokenType.Property: - JProperty property = (JProperty)current; - positions.Add(new JsonPosition(JsonContainerType.Object) { PropertyName = property.Name }); - break; - case JTokenType.Array: - case JTokenType.Constructor: - int index = ((IList)current).IndexOf(next); + case JTokenType.Property: + JProperty property = (JProperty)current; + positions.Add(new JsonPosition(JsonContainerType.Object) { PropertyName = property.Name }); + break; + case JTokenType.Array: + case JTokenType.Constructor: + if (previous != null) + { + int index = ((IList)current).IndexOf(previous); positions.Add(new JsonPosition(JsonContainerType.Array) { Position = index }); - break; - } + } + break; } + + previous = current; } + positions.Reverse(); + return JsonPosition.BuildPath(positions, null); } } @@ -1883,7 +1875,7 @@ namespace Newtonsoft.Json.Linq /// An that can be used to read this token and its descendants. public JsonReader CreateReader() { - return new JTokenReader(this, Path); + return new JTokenReader(this); } internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerializer) diff --git a/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs b/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs index fd10537a..33dd3f13 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs @@ -38,7 +38,7 @@ namespace Newtonsoft.Json.Linq /// The first object of type to compare. /// The second object of type to compare. /// - /// true if the specified objects are equal; otherwise, false. + /// true if the specified objects are equal; otherwise, false. /// public bool Equals(JToken x, JToken y) { diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs index 5f0ca876..0f5c98dc 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs @@ -33,8 +33,8 @@ namespace Newtonsoft.Json.Linq /// public class JTokenReader : JsonReader, IJsonLineInfo { - private readonly string _initialPath; private readonly JToken _root; + private string _initialPath; private JToken _parent; private JToken _current; @@ -57,6 +57,7 @@ namespace Newtonsoft.Json.Linq _root = token; } + // this is used by json.net schema internal JTokenReader(JToken token, string initialPath) : this(token) { @@ -67,7 +68,7 @@ namespace Newtonsoft.Json.Linq /// Reads the next JSON token from the stream. /// /// - /// true if the next token was read successfully; false if there are no more tokens to read. + /// true if the next token was read successfully; false if there are no more tokens to read. /// public override bool Read() { @@ -306,6 +307,11 @@ namespace Newtonsoft.Json.Linq { string path = base.Path; + if (_initialPath == null) + { + _initialPath = _root.Path; + } + if (!string.IsNullOrEmpty(_initialPath)) { if (string.IsNullOrEmpty(path)) diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index 03318509..86e5d954 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -485,5 +485,53 @@ namespace Newtonsoft.Json.Linq AddValue(value, JsonToken.String); } #endregion + + internal override void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments) + { + JTokenReader tokenReader = reader as JTokenReader; + + // closing the token wrather than reading then writing it doesn't lose some type information, e.g. Guid, byte[], etc + if (tokenReader != null && writeChildren && writeDateConstructorAsDate && writeComments) + { + if (tokenReader.TokenType == JsonToken.None) + { + if (!tokenReader.Read()) + { + return; + } + } + + JToken value = tokenReader.CurrentToken.CloneToken(); + + if (_parent != null) + { + _parent.Add(value); + _current = _parent.Last; + + // if the writer was in a property then move out of it and up to its parent object + if (_parent.Type == JTokenType.Property) + { + _parent = _parent.Parent; + InternalWriteValue(JsonToken.Null); + } + } + else + { + _current = value; + + if (_token == null && _value == null) + { + _token = value as JContainer; + _value = value as JValue; + } + } + + tokenReader.Skip(); + } + else + { + base.WriteToken(reader, writeChildren, writeDateConstructorAsDate, writeComments); + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 8dd1297e..d6d6b30e 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -819,11 +819,13 @@ namespace Newtonsoft.Json.Linq writer.WriteValue((byte[])_value); return; case JTokenType.Guid: + writer.WriteValue((_value != null) ? (Guid?)_value : null); + return; case JTokenType.TimeSpan: - writer.WriteValue((_value != null) ? _value.ToString() : null); + writer.WriteValue((_value != null) ? (TimeSpan?)_value : null); return; case JTokenType.Uri: - writer.WriteValue((_value != null) ? ((Uri)_value).OriginalString : null); + writer.WriteValue((Uri)_value); return; } @@ -847,7 +849,7 @@ namespace Newtonsoft.Json.Linq /// Indicates whether the current object is equal to another object of the same type. /// /// - /// true if the current object is equal to the parameter; otherwise, false. + /// true if the current object is equal to the parameter; otherwise, false. /// /// An object to compare with this object. public bool Equals(JValue other) @@ -865,7 +867,7 @@ namespace Newtonsoft.Json.Linq /// /// The to compare with the current . /// - /// true if the specified is equal to the current ; otherwise, false. + /// true if the specified is equal to the current ; otherwise, false. /// /// /// The parameter is null. diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs index 3b5c44e4..ee80d779 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs @@ -76,48 +76,60 @@ namespace Newtonsoft.Json.Linq.JsonPath foreach (JToken r in pathResult) { JValue v = r as JValue; - switch (Operator) + if (v != null) { - case QueryOperator.Equals: - if (v != null && EqualsWithStringCoercion(v, Value)) - { + switch (Operator) + { + case QueryOperator.Equals: + if (EqualsWithStringCoercion(v, Value)) + { + return true; + } + break; + case QueryOperator.NotEquals: + if (!EqualsWithStringCoercion(v, Value)) + { + return true; + } + break; + case QueryOperator.GreaterThan: + if (v.CompareTo(Value) > 0) + { + return true; + } + break; + case QueryOperator.GreaterThanOrEquals: + if (v.CompareTo(Value) >= 0) + { + return true; + } + break; + case QueryOperator.LessThan: + if (v.CompareTo(Value) < 0) + { + return true; + } + break; + case QueryOperator.LessThanOrEquals: + if (v.CompareTo(Value) <= 0) + { + return true; + } + break; + case QueryOperator.Exists: return true; - } - break; - case QueryOperator.NotEquals: - if (v != null && !EqualsWithStringCoercion(v, Value)) - { + } + } + else + { + switch (Operator) + { + case QueryOperator.Exists: + // you can only specify primative types in a comparison + // notequals will always be true + case QueryOperator.NotEquals: return true; - } - break; - case QueryOperator.GreaterThan: - if (v != null && v.CompareTo(Value) > 0) - { - return true; - } - break; - case QueryOperator.GreaterThanOrEquals: - if (v != null && v.CompareTo(Value) >= 0) - { - return true; - } - break; - case QueryOperator.LessThan: - if (v != null && v.CompareTo(Value) < 0) - { - return true; - } - break; - case QueryOperator.LessThanOrEquals: - if (v != null && v.CompareTo(Value) <= 0) - { - return true; - } - break; - case QueryOperator.Exists: - return true; - default: - throw new ArgumentOutOfRangeException(); + } } } diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Dotnet.xproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Dotnet.xproj index c841f384..07d8d0ba 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Dotnet.xproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Dotnet.xproj @@ -9,9 +9,8 @@ 779e052e-7218-4da3-b419-ffb0f4c95081 Newtonsoft.Json ..\artifacts\obj\$(MSBuildProjectName) - ..\artifacts\bin\$(MSBuildProjectName)\ + .\bin\ - 2.0 diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index bfc61ab8..62cc370e 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -32,7 +32,9 @@ using System.Security; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -#if PORTABLE40 +#if NETSTANDARD10 +[assembly: AssemblyTitle("Json.NET .NET Standard 1.0")] +#elif PORTABLE40 [assembly: AssemblyTitle("Json.NET Portable .NET 4.0")] #elif PORTABLE [assembly: AssemblyTitle("Json.NET Portable")] @@ -48,7 +50,6 @@ using System.Security; [assembly: AssemblyTitle("Json.NET .NET 4.0")] [assembly: AllowPartiallyTrustedCallers] #else - [assembly: AssemblyTitle("Json.NET")] [assembly: AllowPartiallyTrustedCallers] #endif diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 3c0b769e..199f925b 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -40,7 +40,6 @@ using System.Runtime.Serialization; #if !(DOTNET || PORTABLE || PORTABLE40) using System.Security.Permissions; #endif -using System.Xml.Serialization; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index ab3829c5..ab566543 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -172,7 +172,10 @@ namespace Newtonsoft.Json.Serialization if (keyType != null && valueType != null) { - _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType)); + _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor( + CreatedType, + typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType), + typeof(IDictionary<,>).MakeGenericType(keyType, valueType)); #if !(NET35 || NET20) if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 7864da5c..ff1be4c8 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -2041,9 +2041,19 @@ namespace Newtonsoft.Json.Serialization IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value; - foreach (DictionaryEntry newValue in newValues) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = newValues.GetEnumerator(); + try { - targetDictionary.Add(newValue.Key, newValue.Value); + while (e.MoveNext()) + { + DictionaryEntry entry = e.Entry; + targetDictionary.Add(entry.Key, entry.Value); + } + } + finally + { + (e as IDisposable)?.Dispose(); } } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index d5b84963..6f2679e9 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -1050,49 +1050,60 @@ namespace Newtonsoft.Json.Serialization int initialDepth = writer.Top; - foreach (DictionaryEntry entry in values) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = values.GetEnumerator(); + try { - bool escape; - string propertyName = GetPropertyName(writer, entry.Key, contract.KeyContract, out escape); - - propertyName = (contract.DictionaryKeyResolver != null) - ? contract.DictionaryKeyResolver(propertyName) - : propertyName; - - try + while (e.MoveNext()) { - object value = entry.Value; - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + DictionaryEntry entry = e.Entry; - if (ShouldWriteReference(value, null, valueContract, contract, member)) + bool escape; + string propertyName = GetPropertyName(writer, entry.Key, contract.KeyContract, out escape); + + propertyName = (contract.DictionaryKeyResolver != null) + ? contract.DictionaryKeyResolver(propertyName) + : propertyName; + + try { - writer.WritePropertyName(propertyName, escape); - WriteReference(writer, value); - } - else - { - if (!CheckForCircularReference(writer, value, null, valueContract, contract, member)) + object value = entry.Value; + JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + + if (ShouldWriteReference(value, null, valueContract, contract, member)) { - continue; + writer.WritePropertyName(propertyName, escape); + WriteReference(writer, value); } + else + { + if (!CheckForCircularReference(writer, value, null, valueContract, contract, member)) + { + continue; + } - writer.WritePropertyName(propertyName, escape); + writer.WritePropertyName(propertyName, escape); - SerializeValue(writer, value, valueContract, null, contract, member); + SerializeValue(writer, value, valueContract, null, contract, member); + } } - } - catch (Exception ex) - { - if (IsErrorHandled(underlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex)) + catch (Exception ex) { - HandleError(writer, initialDepth); - } - else - { - throw; + if (IsErrorHandled(underlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex)) + { + HandleError(writer, initialDepth); + } + else + { + throw; + } } } } + finally + { + (e as IDisposable)?.Dispose(); + } writer.WriteEndObject(); diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs index 6b84fc34..bd504720 100644 --- a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -113,6 +113,13 @@ namespace Newtonsoft.Json.Utilities } public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType) + { + Type genericConstructorArgument = typeof(IList<>).MakeGenericType(collectionItemType); + + return ResolveEnumerableCollectionConstructor(collectionType, collectionItemType, genericConstructorArgument); + } + + public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType) { Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType); ConstructorInfo match = null; @@ -123,7 +130,9 @@ namespace Newtonsoft.Json.Utilities if (parameters.Count == 1) { - if (genericEnumerable == parameters[0].ParameterType) + Type parameterType = parameters[0].ParameterType; + + if (genericEnumerable == parameterType) { // exact match match = constructor; @@ -133,7 +142,7 @@ namespace Newtonsoft.Json.Utilities // incase we can't find an exact match, use first inexact if (match == null) { - if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType)) + if (parameterType.IsAssignableFrom(constructorArgumentType)) { match = constructor; } @@ -214,11 +223,11 @@ namespace Newtonsoft.Json.Utilities return -1; } - public static bool Contains(this IEnumerable list, object value, IEqualityComparer comparer) + public static bool Contains(this List list, T value, IEqualityComparer comparer) { - foreach (object item in list) + for (int i = 0; i < list.Count; i++) { - if (comparer.Equals(item, value)) + if (comparer.Equals(value, list[i])) { return true; } @@ -226,24 +235,14 @@ namespace Newtonsoft.Json.Utilities return false; } - /// - /// Returns the index of the first occurrence in a sequence by using a specified IEqualityComparer{TSource}. - /// - /// The type of the elements of source. - /// A sequence in which to locate a value. - /// The object to locate in the sequence - /// An equality comparer to compare values. - /// The zero-based index of the first occurrence of value within the entire sequence, if found; otherwise, –1. - public static int IndexOf(this IEnumerable list, TSource value, IEqualityComparer comparer) + public static int IndexOfReference(this List list, T item) { - int index = 0; - foreach (TSource item in list) + for (int i = 0; i < list.Count; i++) { - if (comparer.Equals(item, value)) + if (ReferenceEquals(item, list[i])) { - return index; + return i; } - index++; } return -1; } diff --git a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs index 4819c23d..4208513a 100644 --- a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs +++ b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs @@ -299,9 +299,19 @@ namespace Newtonsoft.Json.Utilities { if (_dictionary != null) { - foreach (DictionaryEntry item in _dictionary) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = _dictionary.GetEnumerator(); + try { - array[arrayIndex++] = new KeyValuePair((TKey)item.Key, (TValue)item.Value); + while (e.MoveNext()) + { + DictionaryEntry entry = e.Entry; + array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value); + } + } + finally + { + (e as IDisposable)?.Dispose(); } } #if !(NET40 || NET35 || NET20 || PORTABLE40) diff --git a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs index 13cfe7b0..fdd930b5 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs @@ -240,7 +240,7 @@ namespace Newtonsoft.Json.Utilities public override Func CreateGet(PropertyInfo propertyInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(T), new[] { typeof(object) }, propertyInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateGetPropertyIL(propertyInfo, generator); diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index ba79efca..382d8b02 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -769,9 +769,11 @@ namespace Newtonsoft.Json.Utilities Attribute[] attributes = a.Cast().ToArray(); #if (NET20 || NET35) - // ye olde .NET GetCustomAttributes doesn't respect the inherit argument + // ye olde .NET GetCustomAttributes doesn't respect the inherit argument if (inherit && t.BaseType != null) + { attributes = attributes.Union(GetAttributes(t.BaseType, attributeType, inherit)).ToArray(); + } #endif return attributes; diff --git a/Src/Newtonsoft.Json/project.json b/Src/Newtonsoft.Json/project.json index 2b461622..e8b2eb0f 100644 --- a/Src/Newtonsoft.Json/project.json +++ b/Src/Newtonsoft.Json/project.json @@ -1,14 +1,19 @@ { - "version": "7.0.2-beta1", + "version": "1.0.0-*", "title": "Json.NET", "description": "Json.NET is a popular high-performance JSON framework for .NET", - "authors": [ "James Newton-King" ], - "tags": [ "json" ], - "projectUrl": "http://www.newtonsoft.com/json", - "licenseUrl": "https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md", - "iconUrl": "http://www.newtonsoft.com/content/images/nugeticon.png", "language": "en-US", - + "authors": [ "James Newton-King" ], + "packOptions": { + "projectUrl": "http://www.newtonsoft.com/json", + "tags": [ "json" ], + "licenseUrl": "https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md", + "iconUrl": "http://www.newtonsoft.com/content/images/nugeticon.png", + "repository": { + "type": "git", + "url": "git://github.com/JamesNK/Newtonsoft.Json" + } + }, "frameworks": { "net45": { "frameworkAssemblies": { @@ -44,8 +49,10 @@ } }, ".NETPortable,Version=v4.5,Profile=Profile259": { - "compilationOptions": { - "define": [ "PORTABLE" ] + "buildOptions": { + "define": [ + "PORTABLE" + ] }, "frameworkAssemblies": { "Microsoft.CSharp": "", @@ -61,6 +68,7 @@ "System.ObjectModel": "", "System.Reflection": "", "System.Reflection.Extensions": "", + "System.Resources.ResourceManager": "", "System.Runtime": "", "System.Runtime.Extensions": "", "System.Runtime.Serialization": "", @@ -77,8 +85,10 @@ } }, ".NETPortable,Version=v4.0,Profile=Profile328": { - "compilationOptions": { - "define": [ "PORTABLE40" ] + "buildOptions": { + "define": [ + "PORTABLE40" + ] }, "frameworkAssemblies": { "mscorlib": "", @@ -88,32 +98,36 @@ "System.Xml": "" } }, - "dotnet": { + "netstandard1.0": { + "buildOptions": { + "define": [ + "NETSTANDARD10", + "PORTABLE" + ] + }, "dependencies": { - "Microsoft.CSharp": "4.0.0", - "System.Collections": "4.0.10", - "System.Collections.Concurrent": "4.0.10", - "System.ComponentModel.TypeConverter": "4.0.0", - "System.Diagnostics.Debug": "4.0.10", - "System.Dynamic.Runtime": "4.0.10", - "System.Globalization": "4.0.10", - "System.IO": "4.0.10", - "System.Linq": "4.0.0", - "System.Linq.Expressions": "4.0.10", - "System.ObjectModel": "4.0.10", - "System.Reflection": "4.0.10", - "System.Reflection.Extensions": "4.0.0", - "System.Runtime": "4.0.20", - "System.Runtime.Extensions": "4.0.10", - "System.Runtime.Numerics": "4.0.0", - "System.Runtime.Serialization.Primitives": "4.0.10", - "System.Text.Encoding": "4.0.10", - "System.Text.Encoding.Extensions": "4.0.10", - "System.Text.RegularExpressions": "4.0.10", - "System.Threading": "4.0.10", - "System.Threading.Tasks": "4.0.10", - "System.Xml.ReaderWriter": "4.0.10", - "System.Xml.XDocument": "4.0.10" + "Microsoft.CSharp": "4.0.1-rc2-24027", + "System.Collections": "4.0.11-rc2-24027", + "System.Diagnostics.Debug": "4.0.11-rc2-24027", + "System.Dynamic.Runtime": "4.0.11-rc2-24027", + "System.Globalization": "4.0.11-rc2-24027", + "System.IO": "4.1.0-rc2-24027", + "System.Linq": "4.1.0-rc2-24027", + "System.Linq.Expressions": "4.0.11-rc2-24027", + "System.ObjectModel": "4.0.12-rc2-24027", + "System.Reflection": "4.1.0-rc2-24027", + "System.Reflection.Extensions": "4.0.1-rc2-24027", + "System.Resources.ResourceManager": "4.0.1-rc2-24027", + "System.Runtime": "4.1.0-rc2-24027", + "System.Runtime.Extensions": "4.1.0-rc2-24027", + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027", + "System.Text.Encoding": "4.0.11-rc2-24027", + "System.Text.Encoding.Extensions": "4.0.11-rc2-24027", + "System.Text.RegularExpressions": "4.0.12-rc2-24027", + "System.Threading": "4.0.11-rc2-24027", + "System.Threading.Tasks": "4.0.11-rc2-24027", + "System.Xml.ReaderWriter": "4.0.11-rc2-24027", + "System.Xml.XDocument": "4.0.11-rc2-24027" } } } diff --git a/Src/NuGet.Config b/Src/NuGet.Config index 8b8ba5bc..be824e1a 100644 --- a/Src/NuGet.Config +++ b/Src/NuGet.Config @@ -3,8 +3,8 @@ - - - + + \ No newline at end of file diff --git a/Src/global.json b/Src/global.json index ae0a7539..0ddf69c7 100644 --- a/Src/global.json +++ b/Src/global.json @@ -1,6 +1,3 @@ { - "projects": [ "src" ], - "sdk": { - "version": "1.0.0-rc1-update1" - } -} + "projects": [ "src" ] +} \ No newline at end of file diff --git a/Tools/Dotnet/install.ps1 b/Tools/Dotnet/install.ps1 new file mode 100644 index 00000000..8b0ac72d --- /dev/null +++ b/Tools/Dotnet/install.ps1 @@ -0,0 +1,338 @@ +# +# Copyright (c) .NET Foundation and contributors. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# + +<# +.SYNOPSIS + Installs dotnet cli +.DESCRIPTION + Installs dotnet cli. If dotnet installation already exists in the given directory + it will update it only if the requested version differs from the one already installed. +.PARAMETER Channel + Default: preview + Channel is the way of reasoning about stability and quality of dotnet. This parameter takes one of the values: + - future - Possibly unstable, frequently changing, may contain new finished and unfinished features + - preview - Pre-release stable with known issues and feature gaps + - production - Most stable releases +.PARAMETER Version + Default: latest + Represents a build version on specific channel. Possible values: + - 4-part version in a format A.B.C.D - represents specific version of build + - latest - most latest build on specific channel + - lkg - last known good version on specific channel + Note: LKG work is in progress. Once the work is finished, this will become new default +.PARAMETER InstallDir + Default: %LocalAppData%\Microsoft\dotnet + Path to where to install dotnet. Note that binaries will be placed directly in a given directory. +.PARAMETER Architecture + Default: - this value represents currently running OS architecture + Architecture of dotnet binaries to be installed. + Possible values are: , x64 and x86 +.PARAMETER DebugSymbols + If set the installer will include symbols in the installation. +.PARAMETER DryRun + If set it will not perform installation but instead display what command line to use to consistently install + currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link + with specific version so that this command can be used deterministicly in a build script. + It also displays binaries location if you prefer to install or download it yourself. +.PARAMETER NoPath + By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder. + If set it will display binaries location but not set any environment variable. +.PARAMETER Verbose + Displays diagnostics information. +.PARAMETER AzureFeed + Default: https://dotnetcli.blob.core.windows.net/dotnet + This parameter should not be usually changed by user. It allows to change URL for the Azure feed used by this installer. +#> +[cmdletbinding()] +param( + [string]$Channel="preview", + [string]$Version="Latest", + [string]$InstallDir="", + [string]$Architecture="", + [switch]$DebugSymbols, # TODO: Switch does not work yet. Symbols zip is not being uploaded yet. + [switch]$DryRun, + [switch]$NoPath, + [string]$AzureFeed="https://dotnetcli.blob.core.windows.net/dotnet" +) + +Set-StrictMode -Version Latest +$ErrorActionPreference="Stop" +$ProgressPreference="SilentlyContinue" + +$BinFolderRelativePath="" + +# example path with regex: shared/1.0.0-beta-12345/somepath +$VersionRegEx="/\d+\.\d+[^/]+/" +$OverrideNonVersionedFiles=$true + +function Say($str) { + Write-Host "dotnet_install: $str" +} + +function Say-Verbose($str) { + Write-Verbose "dotnet_install: $str" +} + +function Say-Invocation($Invocation) { + $command = $Invocation.MyCommand; + $args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ") + Say-Verbose "$command $args" +} + +function Get-Machine-Architecture() { + Say-Invocation $MyInvocation + + # possible values: AMD64, IA64, x86 + return $ENV:PROCESSOR_ARCHITECTURE +} + +# TODO: Architecture and CLIArchitecture should be unified +function Get-CLIArchitecture-From-Architecture([string]$Architecture) { + Say-Invocation $MyInvocation + + switch ($Architecture.ToLower()) { + { $_ -eq "" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) } + { ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" } + { $_ -eq "x86" } { return "x86" } + default { throw "Architecture not supported. If you think this is a bug, please report it at https://github.com/dotnet/cli/issues" } + } +} + +function Get-Version-Info-From-Version-Text([string]$VersionText) { + Say-Invocation $MyInvocation + + $Data = @($VersionText.Split([char[]]@(), [StringSplitOptions]::RemoveEmptyEntries)); + + $VersionInfo = @{} + $VersionInfo.CommitHash = $Data[0].Trim() + $VersionInfo.Version = $Data[1].Trim() + return $VersionInfo +} + +function Get-Latest-Version-Info([string]$AzureFeed, [string]$AzureChannel, [string]$CLIArchitecture) { + Say-Invocation $MyInvocation + + $VersionFileUrl = "$AzureFeed/$AzureChannel/dnvm/latest.win.$CLIArchitecture.version" + $Response = Invoke-WebRequest -UseBasicParsing $VersionFileUrl + $VersionText = [Text.Encoding]::UTF8.GetString($Response.Content) + + $VersionInfo = Get-Version-Info-From-Version-Text $VersionText + + return $VersionInfo +} + +# TODO: AzureChannel and Channel should be unified +function Get-Azure-Channel-From-Channel([string]$Channel) { + Say-Invocation $MyInvocation + + # For compatibility with build scripts accept also directly Azure channels names + switch ($Channel.ToLower()) { + { ($_ -eq "future") -or ($_ -eq "dev") } { return "dev" } + { ($_ -eq "preview") -or ($_ -eq "beta") } { return "beta" } + { $_ -eq "production" } { throw "Production channel does not exist yet" } + default { throw "``$Channel`` is an invalid channel name. Use one of the following: ``future``, ``preview``, ``production``" } + } +} + +function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$AzureChannel, [string]$CLIArchitecture, [string]$Version) { + Say-Invocation $MyInvocation + + switch ($Version.ToLower()) { + { $_ -eq "latest" } { + $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -AzureChannel $AzureChannel -CLIArchitecture $CLIArchitecture + return $LatestVersionInfo.Version + } + { $_ -eq "lkg" } { throw "``-Version LKG`` not supported yet." } + default { return $Version } + } +} + +function Get-Download-Links([string]$AzureFeed, [string]$AzureChannel, [string]$SpecificVersion, [string]$CLIArchitecture) { + Say-Invocation $MyInvocation + + $ret = @() + $files = @("dotnet-dev") + + foreach ($file in $files) { + $PayloadURL = "$AzureFeed/$AzureChannel/Binaries/$SpecificVersion/$file-win-$CLIArchitecture.$SpecificVersion.zip" + Say-Verbose "Constructed payload URL: $PayloadURL" + $ret += $PayloadURL + } + + return $ret +} + +function Get-User-Share-Path() { + Say-Invocation $MyInvocation + + $InstallRoot = $env:DOTNET_INSTALL_DIR + if (!$InstallRoot) { + $InstallRoot = "$env:LocalAppData\Microsoft\dotnet" + } + return $InstallRoot +} + +function Resolve-Installation-Path([string]$InstallDir) { + Say-Invocation $MyInvocation + + if ($InstallDir -eq "") { + return Get-User-Share-Path + } + return $InstallDir +} + +function Get-Version-Info-From-Version-File([string]$InstallRoot, [string]$RelativePathToVersionFile) { + Say-Invocation $MyInvocation + + $VersionFile = Join-Path -Path $InstallRoot -ChildPath $RelativePathToVersionFile + Say-Verbose "Local version file: $VersionFile" + + if (Test-Path $VersionFile) { + $VersionText = cat $VersionFile + Say-Verbose "Local version file text: $VersionText" + return Get-Version-Info-From-Version-Text $VersionText + } + + Say-Verbose "Local version file not found." + + return $null +} + +function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) { + Say-Invocation $MyInvocation + + $DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion + Say-Verbose "Is-Dotnet-Package-Installed: Path to a package: $DotnetPackagePath" + return Test-Path $DotnetPackagePath -PathType Container +} + +function Get-Absolute-Path([string]$RelativeOrAbsolutePath) { + # Too much spam + # Say-Invocation $MyInvocation + + return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($RelativeOrAbsolutePath) +} + +function Get-Path-Prefix-With-Version($path) { + $match = [regex]::match($path, $VersionRegEx) + if ($match.Success) { + return $entry.FullName.Substring(0, $match.Index + $match.Length) + } + + return $null +} + +function Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package([System.IO.Compression.ZipArchive]$Zip, [string]$OutPath) { + Say-Invocation $MyInvocation + + $ret = @() + foreach ($entry in $Zip.Entries) { + $dir = Get-Path-Prefix-With-Version $entry.FullName + if ($dir -ne $null) { + $path = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $dir) + if (-Not (Test-Path $path -PathType Container)) { + $ret += $dir + } + } + } + + $ret = $ret | Sort-Object | Get-Unique + + $values = ($ret | foreach { "$_" }) -join ";" + Say-Verbose "Directories to unpack: $values" + + return $ret +} + +# Example zip content and extraction algorithm: +# Rule: files if extracted are always being extracted to the same relative path locally +# .\ +# a.exe # file does not exist locally, extract +# b.dll # file exists locally, override only if $OverrideFiles set +# aaa\ # same rules as for files +# ... +# abc\1.0.0\ # directory contains version and exists locally +# ... # do not extract content under versioned part +# abc\asd\ # same rules as for files +# ... +# def\ghi\1.0.1\ # directory contains version and does not exist locally +# ... # extract content +function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) { + Say-Invocation $MyInvocation + + Add-Type -Assembly System.IO.Compression.FileSystem | Out-Null + Set-Variable -Name Zip + try { + $Zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath) + + $DirectoriesToUnpack = Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package -Zip $Zip -OutPath $OutPath + + foreach ($entry in $Zip.Entries) { + $PathWithVersion = Get-Path-Prefix-With-Version $entry.FullName + if (($PathWithVersion -eq $null) -Or ($DirectoriesToUnpack -contains $PathWithVersion)) { + $DestinationPath = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $entry.FullName) + $DestinationDir = Split-Path -Parent $DestinationPath + $OverrideFiles=$OverrideNonVersionedFiles -Or (-Not (Test-Path $DestinationPath)) + if ((-Not $DestinationPath.EndsWith("\")) -And $OverrideFiles) { + New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $DestinationPath, $OverrideNonVersionedFiles) + } + } + } + } + finally { + if ($Zip -ne $null) { + $Zip.Dispose() + } + } +} + +$AzureChannel = Get-Azure-Channel-From-Channel -Channel $Channel +$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture +$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -AzureChannel $AzureChannel -CLIArchitecture $CLIArchitecture -Version $Version +$DownloadLinks = Get-Download-Links -AzureFeed $AzureFeed -AzureChannel $AzureChannel -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture + +if ($DryRun) { + Say "Payload URLs:" + foreach ($DownloadLink in $DownloadLinks) { + Say "- $DownloadLink" + } + Say "Repeatable invocation: .\$($MyInvocation.MyCommand) -Version $SpecificVersion -Channel $Channel -Architecture $CLIArchitecture -InstallDir $InstallDir" + return +} + +$InstallRoot = Resolve-Installation-Path $InstallDir +Say-Verbose "InstallRoot: $InstallRoot" + +$IsSdkInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage "sdk" -SpecificVersion $SpecificVersion +Say-Verbose ".NET SDK installed? $IsSdkInstalled" +if ($IsSdkInstalled) { + Say ".NET SDK version $SpecificVersion is already installed." + return +} + +New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null + +foreach ($DownloadLink in $DownloadLinks) { + $ZipPath = [System.IO.Path]::GetTempFileName() + Say "Downloading $DownloadLink" + $resp = Invoke-WebRequest -UseBasicParsing $DownloadLink -OutFile $ZipPath + + Say "Extracting zip from $DownloadLink" + Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot + + Remove-Item $ZipPath +} + +$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath) +if (-Not $NoPath) { + Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process." + $env:path += ";$BinPath" +} +else { + Say "Binaries of dotnet can be found in $BinPath" +} + +Say "Installation finished" diff --git a/Tools/NuGet/NuGet.exe b/Tools/NuGet/NuGet.exe index 9f8781de..31fc9885 100644 Binary files a/Tools/NuGet/NuGet.exe and b/Tools/NuGet/NuGet.exe differ