diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 2b469ddd92bcee..058644afd46753 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25103.3", + "version": "9.0.0-prerelease.25113.3", "commands": [ "xharness" ] diff --git a/NuGet.config b/NuGet.config index 7a77a883fb2871..deafa2a01414c9 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,28 +9,10 @@ - - - - - - - - - - - - - - - - - - - + - + - + https://github.com/dotnet/cecil - aa3ae0d49da3cfb31a383f16303a3f2f0c3f1a19 + 8debcd23b73a27992a5fdb2229f546e453619d11 - + https://github.com/dotnet/emsdk - dad5528e5bdf92a05a5a404c5f7939523390b96d + 78be8cdf4f0bfd93018fd7a87f8282a41d041298 - + https://github.com/dotnet/emsdk - dad5528e5bdf92a05a5a404c5f7939523390b96d + 78be8cdf4f0bfd93018fd7a87f8282a41d041298 - + https://github.com/dotnet/emsdk - dad5528e5bdf92a05a5a404c5f7939523390b96d + 78be8cdf4f0bfd93018fd7a87f8282a41d041298 @@ -92,195 +92,195 @@ - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 https://github.com/dotnet/runtime @@ -320,21 +320,21 @@ https://github.com/dotnet/runtime b030c4dfdfa1bf287f10f96006619a06bc2000ae - + https://github.com/dotnet/xharness - 22a44bd14f5d6308acdda4b6dd67e4d7aa0bca5b + edc52ac68c1bf77e3b107fc8a448674a6d058d8a - + https://github.com/dotnet/xharness - 22a44bd14f5d6308acdda4b6dd67e4d7aa0bca5b + edc52ac68c1bf77e3b107fc8a448674a6d058d8a - + https://github.com/dotnet/xharness - 22a44bd14f5d6308acdda4b6dd67e4d7aa0bca5b + edc52ac68c1bf77e3b107fc8a448674a6d058d8a - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + f33d9e642f0e68a61312164cd9e0baf4e142a999 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -352,48 +352,48 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://github.com/dotnet/hotreload-utils - fe67b0da4c0a7e82f0f9a4da1cb966c730e6934f + fd21b154f1152569e7fa49a4e030927eccbf4aaa - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/sdk - 049799c39d766c58ef6388865d5f5ed273b6a75e + 346d06baea1cf7113e181e779b056b955973c633 - + https://github.com/dotnet/sdk - 049799c39d766c58ef6388865d5f5ed273b6a75e + 346d06baea1cf7113e181e779b056b955973c633 diff --git a/eng/Versions.props b/eng/Versions.props index 9bc7f6caeff393..8ba353723841c2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 9.0.3 + 9.0.4 9 0 - 3 + 4 9.0.100 8.0.$([MSBuild]::Add($(PatchVersion),11)) 7.0.20 @@ -36,17 +36,17 @@ - 3.11.0-beta1.25076.3 - 9.0.0-preview.25076.3 + 3.11.0-beta1.25123.3 + 9.0.0-preview.25123.3 - 4.12.0-3.25105.5 - 4.12.0-3.25105.5 - 4.12.0-3.25105.5 + 4.12.0-3.25124.2 + 4.12.0-3.25124.2 + 4.12.0-3.25124.2 - 9.0.103 + 9.0.104 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 2.9.0-beta.25077.4 - 9.0.0-beta.25077.4 - 2.9.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 2.9.0-beta.25161.4 + 9.0.0-beta.25161.4 + 2.9.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 1.4.0 @@ -141,20 +141,20 @@ 8.0.0 8.0.0 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 @@ -184,10 +184,10 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.25103.3 - 9.0.0-prerelease.25103.3 - 9.0.0-prerelease.25103.3 - 9.0.0-alpha.0.25077.3 + 9.0.0-prerelease.25113.3 + 9.0.0-prerelease.25113.3 + 9.0.0-prerelease.25113.3 + 9.0.0-alpha.0.25153.2 3.12.0 4.5.0 6.0.0 @@ -215,55 +215,55 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25102.5 + 0.11.5-alpha.25112.2 9.0.0-rtm.24511.16 - 9.0.0-rtm.25105.1 + 9.0.0-rtm.25157.1 9.0.0-rtm.24466.4 - 2.4.3 + 2.4.8 9.0.0-alpha.1.24167.3 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 - 9.0.3-servicing.25105.2 - 9.0.3 + 9.0.4-servicing.25157.2 + 9.0.4 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100Version) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 3.1.7 1.0.406601 - - 9.0.102 + $(MicrosoftDotNetApiCompatTaskVersion) + 9.0.0-alpha.1.24175.1 $(MicrosoftNETRuntimeEmscriptenVersion) $(runtimewinx64MicrosoftNETCoreRuntimeWasmNodeTransportPackageVersion) diff --git a/eng/common/core-templates/steps/generate-sbom.yml b/eng/common/core-templates/steps/generate-sbom.yml index d938b60e1bb534..56a090094824f4 100644 --- a/eng/common/core-templates/steps/generate-sbom.yml +++ b/eng/common/core-templates/steps/generate-sbom.yml @@ -38,7 +38,7 @@ steps: PackageName: ${{ parameters.packageName }} BuildDropPath: ${{ parameters.buildDropPath }} PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} + ManifestDirPath: ${{ parameters.manifestDirPath }}/$(ARTIFACT_NAME) ${{ if ne(parameters.IgnoreDirectories, '') }}: AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' diff --git a/eng/common/generate-sbom-prep.ps1 b/eng/common/generate-sbom-prep.ps1 index 3e5c1c74a1c50d..a0c7d792a76fbe 100644 --- a/eng/common/generate-sbom-prep.ps1 +++ b/eng/common/generate-sbom-prep.ps1 @@ -4,18 +4,26 @@ Param( . $PSScriptRoot\pipeline-logging-functions.ps1 +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +$ArtifactName = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" +$SafeArtifactName = $ArtifactName -replace '["/:<>\\|?@*"() ]', '_' +$SbomGenerationDir = Join-Path $ManifestDirPath $SafeArtifactName + +Write-Host "Artifact name before : $ArtifactName" +Write-Host "Artifact name after : $SafeArtifactName" + Write-Host "Creating dir $ManifestDirPath" + # create directory for sbom manifest to be placed -if (!(Test-Path -path $ManifestDirPath)) +if (!(Test-Path -path $SbomGenerationDir)) { - New-Item -ItemType Directory -path $ManifestDirPath - Write-Host "Successfully created directory $ManifestDirPath" + New-Item -ItemType Directory -path $SbomGenerationDir + Write-Host "Successfully created directory $SbomGenerationDir" } else{ Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." } Write-Host "Updating artifact name" -$artifact_name = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" -replace '["/:<>\\|?@*"() ]', '_' -Write-Host "Artifact name $artifact_name" -Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$artifact_name" +Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$SafeArtifactName" diff --git a/eng/common/generate-sbom-prep.sh b/eng/common/generate-sbom-prep.sh index d5c76dc827b496..b8ecca72bbf506 100644 --- a/eng/common/generate-sbom-prep.sh +++ b/eng/common/generate-sbom-prep.sh @@ -14,19 +14,24 @@ done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" . $scriptroot/pipeline-logging-functions.sh + +# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. +artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" +safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" manifest_dir=$1 -if [ ! -d "$manifest_dir" ] ; then - mkdir -p "$manifest_dir" - echo "Sbom directory created." $manifest_dir +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +sbom_generation_dir="$manifest_dir/$safe_artifact_name" + +if [ ! -d "$sbom_generation_dir" ] ; then + mkdir -p "$sbom_generation_dir" + echo "Sbom directory created." $sbom_generation_dir else Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." fi -artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" echo "Artifact name before : "$artifact_name -# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. -safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" echo "Artifact name after : "$safe_artifact_name export ARTIFACT_NAME=$safe_artifact_name echo "##vso[task.setvariable variable=ARTIFACT_NAME]$safe_artifact_name" diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml index 605692d2fb770c..817555505aa602 100644 --- a/eng/common/templates-official/job/job.yml +++ b/eng/common/templates-official/job/job.yml @@ -16,6 +16,7 @@ jobs: parameters: PackageVersion: ${{ parameters.packageVersion }} BuildDropPath: ${{ parameters.buildDropPath }} + ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom publishArtifacts: false # publish artifacts diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh index 41895e0b9254c8..f8c9db632860de 100755 --- a/eng/install-native-dependencies.sh +++ b/eng/install-native-dependencies.sh @@ -44,7 +44,7 @@ case "$os" in export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 # Skip brew update for now, see https://github.com/actions/setup-python/issues/577 # brew update --preinstall - brew bundle --no-upgrade --no-lock --file "$(dirname "$0")/Brewfile" + brew bundle --no-upgrade --file "$(dirname "$0")/Brewfile" ;; *) diff --git a/eng/packaging.targets b/eng/packaging.targets index 0bef49c86a16e7..a14c954df54dbc 100644 --- a/eng/packaging.targets +++ b/eng/packaging.targets @@ -133,7 +133,7 @@ - <_RuntimeSymbolPath Include="$(RuntimeSymbolPath)" /> + <_RuntimeSymbolPath Include="@(TfmRuntimeSpecificPackageFile->'%(RootDir)%(Directory)%(FileName).pdb')" Condition="'%(TfmRuntimeSpecificPackageFile.Extension)' == '.dll'" KeepMetadata="None" /> true - - - false - - diff --git a/src/coreclr/.nuget/Directory.Build.targets b/src/coreclr/.nuget/Directory.Build.targets index 379fbd65030b32..f30471ded8ae4f 100644 --- a/src/coreclr/.nuget/Directory.Build.targets +++ b/src/coreclr/.nuget/Directory.Build.targets @@ -4,7 +4,7 @@ $(ProductVersion) - $(PackageVersion) + $(PackageVersion) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 3d61a698a08d5c..f720ca6c826cba 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2211,6 +2211,22 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree) // If op1 is lcl and op2 is const or lcl, create assertion. if ((op1->gtOper == GT_LCL_VAR) && (op2->OperIsConst() || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483 { + // Watch out for cases where long local(s) are implicitly truncated. + // + LclVarDsc* const lcl1Dsc = lvaGetDesc(op1->AsLclVarCommon()); + if ((lcl1Dsc->TypeGet() == TYP_LONG) && (op1->TypeGet() != TYP_LONG)) + { + return NO_ASSERTION_INDEX; + } + if (op2->OperIs(GT_LCL_VAR)) + { + LclVarDsc* const lcl2Dsc = lvaGetDesc(op2->AsLclVarCommon()); + if ((lcl2Dsc->TypeGet() == TYP_LONG) && (op2->TypeGet() != TYP_LONG)) + { + return NO_ASSERTION_INDEX; + } + } + return optCreateJtrueAssertions(op1, op2, assertionKind); } else if (!optLocalAssertionProp) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 2a5c947de175c5..624a737234fcbb 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -217,7 +217,6 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && id->idIsTlsGD()) { - assert(isGeneralRegister(id->idReg1())); assert(id->idAddr()->iiaAddr != nullptr); } else @@ -9184,11 +9183,14 @@ void emitter::emitIns_Call(EmitCallType callType, if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && EA_IS_CNS_TLSGD_RELOC(retSize)) { // For NativeAOT linux/arm64, we need to also record the relocation of methHnd. - // Since we do not have space to embed it in instrDesc, we store the register in - // reg1 and instead use the `iiaAdd` to store the method handle. Likewise, during - // emitOutputInstr, we retrieve the register from reg1 for this specific case. + // Since we do not have space to embed it in instrDesc, we use the `iiaAddr` to + // store the method handle. + // The target handle need to be always in R2 and hence the assert check. + // We cannot use reg1 and reg2 fields of instrDesc because they contain the gc + // registers (emitEncodeCallGCregs()) that are live across the call. + + assert(ireg == REG_R2); id->idSetTlsGD(); - id->idReg1(ireg); id->idAddr()->iiaAddr = (BYTE*)methHnd; } else @@ -10990,12 +10992,13 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { emitRecordRelocation(odst, (CORINFO_METHOD_HANDLE)id->idAddr()->iiaAddr, IMAGE_REL_AARCH64_TLSDESC_CALL); - code |= insEncodeReg_Rn(id->idReg1()); // nnnnn + code |= insEncodeReg_Rn(REG_R2); // nnnnn } else { code |= insEncodeReg_Rn(id->idReg3()); // nnnnn } + dst += emitOutputCall(ig, dst, id, code); sz = id->idIsLargeCall() ? sizeof(instrDescCGCA) : sizeof(instrDesc); break; @@ -13315,7 +13318,15 @@ void emitter::emitDispInsHelp( case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn // The size of a branch target is always EA_PTRSIZE assert(insOptsNone(id->idInsOpt())); - emitDispReg(id->idReg3(), EA_PTRSIZE, false); + + if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && id->idIsTlsGD()) + { + emitDispReg(REG_R2, EA_PTRSIZE, false); + } + else + { + emitDispReg(id->idReg3(), EA_PTRSIZE, false); + } break; case IF_LS_1A: // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB) diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp index 3f54dbff556af2..8594e62c9a0e6b 100644 --- a/src/coreclr/vm/peassembly.cpp +++ b/src/coreclr/vm/peassembly.cpp @@ -518,7 +518,6 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, } CONTRACTL_END; - mdToken mdLinkRef; DWORD dwResourceFlags; DWORD dwOffset; @@ -567,30 +566,31 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, } - switch(TypeFromToken(mdLinkRef)) { + switch(TypeFromToken(mdLinkRef)) + { case mdtAssemblyRef: { if (pAssembly == NULL) return FALSE; AssemblySpec spec; - spec.InitializeSpec(mdLinkRef, GetMDImport(), pAssembly); - DomainAssembly* pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); + spec.InitializeSpec(mdLinkRef, pAssembly->GetMDImport(), pAssembly); + Assembly* pLoadedAssembly = spec.LoadAssembly(FILE_LOADED); if (dwLocation) { if (pAssemblyRef) - *pAssemblyRef = pDomainAssembly->GetAssembly(); + *pAssemblyRef = pLoadedAssembly; *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly } - return GetResource(szName, - cbResource, - pbInMemoryResource, - pAssemblyRef, - szFileName, - dwLocation, - pDomainAssembly->GetAssembly()); + return pLoadedAssembly->GetResource( + szName, + cbResource, + pbInMemoryResource, + pAssemblyRef, + szFileName, + dwLocation); } case mdtFile: diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs index 90c0ba997cd962..512242230093ff 100644 --- a/src/libraries/Common/src/Interop/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs @@ -157,6 +157,8 @@ internal enum LdapOption LDAP_OPT_ROOTDSE_CACHE = 0x9a, // Not Supported in Linux LDAP_OPT_DEBUG_LEVEL = 0x5001, LDAP_OPT_URI = 0x5006, // Not Supported in Windows + LDAP_OPT_X_TLS_CACERTDIR = 0x6003, // Not Supported in Windows + LDAP_OPT_X_TLS_NEWCTX = 0x600F, // Not Supported in Windows LDAP_OPT_X_SASL_REALM = 0x6101, LDAP_OPT_X_SASL_AUTHCID = 0x6102, LDAP_OPT_X_SASL_AUTHZID = 0x6103 diff --git a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml index 3523d7762232af..1a7f36e6f047bd 100644 --- a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml +++ b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml @@ -1,6 +1,6 @@ -To enable the tests marked with [ConditionalFact(nameof(IsLdapConfigurationExist))], you need to setup an LDAP server and provide the needed server info here. +To enable the tests marked with [ConditionalFact(nameof(IsLdapConfigurationExist))], you need to setup an LDAP server as described below and set the environment variable LDAP_TEST_SERVER_INDEX to the appropriate offset into the XML section found at the end of this file. To ship, we should test on both an Active Directory LDAP server, and at least one other server, as behaviors are a little different. However for local testing, it is easiest to connect to an OpenDJ LDAP server in a docker container (eg., in WSL2). @@ -11,7 +11,7 @@ OPENDJ SERVER test it with this command - it should return some results in WSL2 - ldapsearch -h localhost -p 1389 -D 'cn=admin,dc=example,dc=com' -x -w password + ldapsearch -H ldap://localhost:1389 -D 'cn=admin,dc=example,dc=com' -x -w password this command views the status @@ -24,16 +24,16 @@ SLAPD OPENLDAP SERVER and to test and view status - ldapsearch -h localhost -p 390 -D 'cn=admin,dc=example,dc=com' -x -w password + ldapsearch -H ldap://localhost:390 -D 'cn=admin,dc=example,dc=com' -x -w password docker exec -it slapd01 slapcat SLAPD OPENLDAP SERVER WITH TLS ============================== -The osixia/openldap container image automatically creates a TLS lisener with a self-signed certificate. This can be used to test TLS. +The osixia/openldap container image automatically creates a TLS listener with a self-signed certificate. This can be used to test TLS. -Start the container, with TLS on port 1636, without client certificate verification: +Start the container, with TLS on port 1636, but without client certificate verification: docker run --publish 1389:389 --publish 1636:636 --name ldap --hostname ldap.local --detach --rm --env LDAP_TLS_VERIFY_CLIENT=never --env LDAP_ADMIN_PASSWORD=password osixia/openldap --loglevel debug @@ -56,6 +56,8 @@ To test and view the status: ldapsearch -H ldaps://ldap.local:1636 -b dc=example,dc=org -x -D cn=admin,dc=example,dc=org -w password +use '-d 1' or '-d 2' for debugging. + ACTIVE DIRECTORY ================ @@ -65,7 +67,7 @@ When running against Active Directory from a Windows client, you should not see If you are running your AD server as a VM on the same machine that you are running WSL2, you must execute this command on the host to bridge the two Hyper-V networks so that it is visible from WSL2: - Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled + Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled The WSL2 VM should now be able to see the AD VM by IP address. To make it visible by host name, it's probably easiest to just add it to /etc/hosts. @@ -82,7 +84,7 @@ Note: @@ -105,15 +107,6 @@ Note: ServerBind,None False - - danmose-ldap.danmose-domain.com - DC=danmose-domain,DC=com - 389 - danmose-domain\Administrator - %TESTPASSWORD% - ServerBind,None - True - ldap.local DC=example,DC=org @@ -124,5 +117,14 @@ Note: true False + + danmose-ldap.danmose-domain.com + DC=danmose-domain,DC=com + 389 + danmose-domain\Administrator + %TESTPASSWORD% + ServerBind,None + True + diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs index 6a166b298cd517..1cd57d147a77ed 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs @@ -26,6 +26,7 @@ public static partial class PlatformDetection public static bool IsWindows10OrLater => IsWindowsVersionOrLater(10, 0); public static bool IsWindowsServer2019 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 17763; public static bool IsWindowsServer2022 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 20348; + public static bool IsWindowsServer2025 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 26100; public static bool IsWindowsNanoServer => IsWindows && (IsNotWindowsIoTCore && GetWindowsInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase)); public static bool IsWindowsServerCore => IsWindows && GetWindowsInstallationType().Equals("Server Core", StringComparison.OrdinalIgnoreCase); public static int WindowsVersion => IsWindows ? (int)GetWindowsVersion() : -1; diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 2316c532efb58b..f110b765c8adcd 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -25,7 +25,7 @@ System.Diagnostics.DiagnosticSource - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs index 0c23059c17ae88..ecfe219e072843 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs @@ -145,6 +145,7 @@ public async Task TestBasicReceiveAndResponseEvents() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/112792")] [OuterLoop] [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void TestW3CHeaders() @@ -194,6 +195,7 @@ public void TestW3CHeadersTraceStateAndCorrelationContext() { using (var eventRecords = new EventObserverAndRecorder()) { + Activity.DefaultIdFormat = ActivityIdFormat.W3C; var parent = new Activity("w3c activity"); parent.SetParentId(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom()); parent.TraceStateString = "some=state"; diff --git a/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs b/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs index 32262da81be3e2..126be30b3ddb26 100644 --- a/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs +++ b/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs @@ -382,6 +382,8 @@ public partial class LdapSessionOptions internal LdapSessionOptions() { } public bool AutoReconnect { get { throw null; } set { } } public string DomainName { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")] + public string TrustedCertificatesDirectory { get { throw null; } set { } } public string HostName { get { throw null; } set { } } public bool HostReachable { get { throw null; } } public System.DirectoryServices.Protocols.LocatorFlags LocatorFlag { get { throw null; } set { } } @@ -402,6 +404,8 @@ internal LdapSessionOptions() { } public bool Signing { get { throw null; } set { } } public System.DirectoryServices.Protocols.SecurityPackageContextConnectionInformation SslInformation { get { throw null; } } public int SspiFlag { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")] + public void StartNewTlsSessionContext() { } public bool TcpKeepAlive { get { throw null; } set { } } public System.DirectoryServices.Protocols.VerifyServerCertificateCallback VerifyServerCertificate { get { throw null; } set { } } public void FastConcurrentBind() { } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml b/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml new file mode 100644 index 00000000000000..2647f901c1a47e --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml @@ -0,0 +1,67 @@ + + + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx b/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx index b63f103619fbdb..1f6c9734a7384c 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx +++ b/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx @@ -426,4 +426,7 @@ Only ReferralChasingOptions.None and ReferralChasingOptions.All are supported on Linux. + + The directory '{0}' does not exist. + \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs index 1125bfd568d385..facdfc6a484bb9 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs @@ -955,13 +955,13 @@ private unsafe Interop.BOOL ProcessClientCertificate(IntPtr ldapHandle, IntPtr C private void Connect() { - //Ccurrently ldap does not accept more than one certificate. + // Currently ldap does not accept more than one certificate. if (ClientCertificates.Count > 1) { throw new InvalidOperationException(SR.InvalidClientCertificates); } - // Set the certificate callback routine here if user adds the certifcate to the certificate collection. + // Set the certificate callback routine here if user adds the certificate to the certificate collection. if (ClientCertificates.Count != 0) { int certError = LdapPal.SetClientCertOption(_ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _clientCertificateRoutine); diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs index e1cfffebb531fc..5059c40499d5c6 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.IO; +using System.Runtime.Versioning; namespace System.DirectoryServices.Protocols { @@ -11,6 +13,34 @@ public partial class LdapSessionOptions private bool _secureSocketLayer; + /// + /// Specifies the path of the directory containing CA certificates in the PEM format. + /// Multiple directories may be specified by separating with a semi-colon. + /// + /// + /// The certificate files are looked up by the CA subject name hash value where that hash can be + /// obtained by using, for example, openssl x509 -hash -noout -in CA.crt. + /// It is a common practice to have the certificate file be a symbolic link to the actual certificate file + /// which can be done by using openssl rehash . or c_rehash . in the directory + /// containing the certificate files. + /// + /// The directory not exist. + [UnsupportedOSPlatform("windows")] + public string TrustedCertificatesDirectory + { + get => GetStringValueHelper(LdapOption.LDAP_OPT_X_TLS_CACERTDIR, releasePtr: true); + + set + { + if (!Directory.Exists(value)) + { + throw new DirectoryNotFoundException(SR.Format(SR.DirectoryNotFound, value)); + } + + SetStringOptionHelper(LdapOption.LDAP_OPT_X_TLS_CACERTDIR, value); + } + } + public bool SecureSocketLayer { get @@ -52,6 +82,16 @@ public ReferralChasingOptions ReferralChasing } } + /// + /// Create a new TLS library context. + /// Calling this is necessary after setting TLS-based options, such as TrustedCertificatesDirectory. + /// + [UnsupportedOSPlatform("windows")] + public void StartNewTlsSessionContext() + { + SetIntValueHelper(LdapOption.LDAP_OPT_X_TLS_NEWCTX, 0); + } + private bool GetBoolValueHelper(LdapOption option) { if (_connection._disposed) throw new ObjectDisposedException(GetType().Name); @@ -71,5 +111,14 @@ private void SetBoolValueHelper(LdapOption option, bool value) ErrorChecking.CheckAndSetLdapError(error); } + + private void SetStringOptionHelper(LdapOption option, string value) + { + if (_connection._disposed) throw new ObjectDisposedException(GetType().Name); + + int error = LdapPal.SetStringOption(_connection._ldapHandle, option, value); + + ErrorChecking.CheckAndSetLdapError(error); + } } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs index 813005c5ecb72b..cc73449104adf4 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs @@ -10,6 +10,13 @@ public partial class LdapSessionOptions { private static void PALCertFreeCRLContext(IntPtr certPtr) => Interop.Ldap.CertFreeCRLContext(certPtr); + [UnsupportedOSPlatform("windows")] + public string TrustedCertificatesDirectory + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + public bool SecureSocketLayer { get @@ -24,6 +31,9 @@ public bool SecureSocketLayer } } + [UnsupportedOSPlatform("windows")] + public void StartNewTlsSessionContext() => throw new PlatformNotSupportedException(); + public int ProtocolVersion { get => GetIntValueHelper(LdapOption.LDAP_OPT_VERSION); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs index 00433bae9875c2..05dda66bbda001 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Diagnostics; using System.DirectoryServices.Tests; using System.Globalization; +using System.IO; using System.Net; -using System.Text; -using System.Threading; using Xunit; namespace System.DirectoryServices.Protocols.Tests @@ -16,6 +14,7 @@ public partial class DirectoryServicesProtocolsTests { internal static bool LdapConfigurationExists => LdapConfiguration.Configuration != null; internal static bool IsActiveDirectoryServer => LdapConfigurationExists && LdapConfiguration.Configuration.IsActiveDirectoryServer; + internal static bool UseTls => LdapConfigurationExists && LdapConfiguration.Configuration.UseTls; internal static bool IsServerSideSortSupported => LdapConfigurationExists && LdapConfiguration.Configuration.SupportsServerSideSort; @@ -706,6 +705,64 @@ public void TestMultipleServerBind() connection.Timeout = new TimeSpan(0, 3, 0); } +#if NET + [ConditionalFact(nameof(UseTls))] + [PlatformSpecific(TestPlatforms.Linux)] + public void StartNewTlsSessionContext() + { + using (var connection = GetConnection(bind: false)) + { + // We use "." as the directory since it must be a valid directory for StartNewTlsSessionContext() + Bind() to be successful even + // though there are no client certificates in ".". + connection.SessionOptions.TrustedCertificatesDirectory = "."; + + // For a real-world scenario, we would call 'StartTransportLayerSecurity(null)' here which would do the TLS handshake including + // providing the client certificate to the server and validating the server certificate. However, this requires additional + // setup that we don't have including trusting the server certificate and by specifying "demand" in the setup of the server + // via 'LDAP_TLS_VERIFY_CLIENT=demand' to force the TLS handshake to occur. + + connection.SessionOptions.StartNewTlsSessionContext(); + connection.Bind(); + + SearchRequest searchRequest = new (LdapConfiguration.Configuration.SearchDn, "(objectClass=*)", SearchScope.Subtree); + _ = (SearchResponse)connection.SendRequest(searchRequest); + } + } + + [ConditionalFact(nameof(UseTls))] + [PlatformSpecific(TestPlatforms.Linux)] + public void StartNewTlsSessionContext_ThrowsLdapException() + { + using (var connection = GetConnection(bind: false)) + { + // Create a new session context without setting TrustedCertificatesDirectory. + connection.SessionOptions.StartNewTlsSessionContext(); + Assert.Throws(() => connection.Bind()); + } + } + + [ConditionalFact(nameof(LdapConfigurationExists))] + [PlatformSpecific(TestPlatforms.Linux)] + public void TrustedCertificatesDirectory_ThrowsDirectoryNotFoundException() + { + using (var connection = GetConnection(bind: false)) + { + Assert.Throws(() => connection.SessionOptions.TrustedCertificatesDirectory = "nonexistent"); + } + } + + [ConditionalFact(nameof(LdapConfigurationExists))] + [PlatformSpecific(TestPlatforms.Windows)] + public void StartNewTlsSessionContext_ThrowsPlatformNotSupportedException() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Throws(() => options.StartNewTlsSessionContext()); + } + } +#endif + private void DeleteAttribute(LdapConnection connection, string entryDn, string attributeName) { string dn = entryDn + "," + LdapConfiguration.Configuration.SearchDn; @@ -786,24 +843,24 @@ private SearchResultEntry SearchUser(LdapConnection connection, string rootDn, s return null; } - private LdapConnection GetConnection(string server) + private static LdapConnection GetConnection(string server) { LdapDirectoryIdentifier directoryIdentifier = new LdapDirectoryIdentifier(server, fullyQualifiedDnsHostName: true, connectionless: false); return GetConnection(directoryIdentifier); } - private LdapConnection GetConnection() + private static LdapConnection GetConnection(bool bind = true) { LdapDirectoryIdentifier directoryIdentifier = string.IsNullOrEmpty(LdapConfiguration.Configuration.Port) ? new LdapDirectoryIdentifier(LdapConfiguration.Configuration.ServerName, fullyQualifiedDnsHostName: true, connectionless: false) : new LdapDirectoryIdentifier(LdapConfiguration.Configuration.ServerName, int.Parse(LdapConfiguration.Configuration.Port, NumberStyles.None, CultureInfo.InvariantCulture), fullyQualifiedDnsHostName: true, connectionless: false); - return GetConnection(directoryIdentifier); + return GetConnection(directoryIdentifier, bind); } - private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIdentifier) + private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIdentifier, bool bind = true) { NetworkCredential credential = new NetworkCredential(LdapConfiguration.Configuration.UserName, LdapConfiguration.Configuration.Password); @@ -816,7 +873,11 @@ private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIde // to LDAP v2, which we do not support, and will return LDAP_PROTOCOL_ERROR connection.SessionOptions.ProtocolVersion = 3; connection.SessionOptions.SecureSocketLayer = LdapConfiguration.Configuration.UseTls; - connection.Bind(); + + if (bind) + { + connection.Bind(); + } connection.Timeout = new TimeSpan(0, 3, 0); return connection; diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs index 5f6a737834ac23..2a8ab23a16d421 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs @@ -7,6 +7,8 @@ namespace System.DirectoryServices.Protocols.Tests { + // To enable these tests locally for Mono, comment out this line in DirectoryServicesTestHelpers.cs: + // [assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/35912", TestRuntimes.Mono)] [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class LdapSessionOptionsTests { @@ -27,6 +29,7 @@ public void ReferralChasing_Set_GetReturnsExpected_On_Windows(ReferralChasingOpt } [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/112146")] [PlatformSpecific(TestPlatforms.Linux)] [InlineData(ReferralChasingOptions.None)] [InlineData(ReferralChasingOptions.All)] @@ -756,5 +759,32 @@ public void StopTransportLayerSecurity_Disposed_ThrowsObjectDisposedException() Assert.Throws(() => connection.SessionOptions.StopTransportLayerSecurity()); } + +#if NET + [Fact] + [PlatformSpecific(TestPlatforms.Linux)] + public void CertificateDirectoryProperty() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Null(options.TrustedCertificatesDirectory); + + options.TrustedCertificatesDirectory = "."; + Assert.Equal(".", options.TrustedCertificatesDirectory); + } + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void CertificateDirectoryProperty_ThrowsPlatformNotSupportedException() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Throws(() => options.TrustedCertificatesDirectory = "CertificateDirectory"); + } + } +#endif } } diff --git a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs index 5cb53aa2997e06..ef043f9f6755e7 100644 --- a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs @@ -430,9 +430,12 @@ public override Iterator Take(int count) { if (_source is Iterator iterator && iterator.GetCount(onlyIfCheap: true) is int count && - count >= _minIndexInclusive) + count > _minIndexInclusive) { - return !HasLimit ? + // If there's no upper bound, or if there are fewer items in the list + // than the upper bound allows, just return the last element of the list. + // Otherwise, get the element at the upper bound. + return (uint)count <= (uint)_maxIndexInclusive ? iterator.TryGetLast(out found) : iterator.TryGetElementAt(_maxIndexInclusive, out found); } diff --git a/src/libraries/System.Linq/tests/AggregateByTests.cs b/src/libraries/System.Linq/tests/AggregateByTests.cs index b574660c9e5ac8..43b9262f78b813 100644 --- a/src/libraries/System.Linq/tests/AggregateByTests.cs +++ b/src/libraries/System.Linq/tests/AggregateByTests.cs @@ -11,10 +11,10 @@ public class AggregateByTests : EnumerableTests [Fact] public void Empty() { - Assert.All(IdentityTransforms(), transform => + Assert.All(CreateSources([]), source => { - Assert.Equal(Enumerable.Empty>(), transform(Enumerable.Empty()).AggregateBy(i => i, i => i, (a, i) => a + i)); - Assert.Equal(Enumerable.Empty>(), transform(Enumerable.Empty()).AggregateBy(i => i, 0, (a, i) => a + i)); + Assert.Equal([], source.AggregateBy(i => i, i => i, (a, i) => a + i)); + Assert.Equal([], source.AggregateBy(i => i, 0, (a, i) => a + i)); }); } diff --git a/src/libraries/System.Linq/tests/ChunkTests.cs b/src/libraries/System.Linq/tests/ChunkTests.cs index 31433ddabff30f..1a12ac7fd6765d 100644 --- a/src/libraries/System.Linq/tests/ChunkTests.cs +++ b/src/libraries/System.Linq/tests/ChunkTests.cs @@ -42,10 +42,8 @@ public void ChunkSourceLazily() [InlineData(new[] {9999, 0, 888, -1, 66, -777, 1, 2, -12345})] public void ChunkSourceRepeatCalls(int[] array) { - Assert.All(IdentityTransforms(), t => + Assert.All(CreateSources(array), source => { - IEnumerable source = t(array); - Assert.Equal(source.Chunk(3), source.Chunk(3)); }); } @@ -54,10 +52,8 @@ public void ChunkSourceRepeatCalls(int[] array) [InlineData(new[] {9999, 0, 888, -1, 66, -777, 1, 2, -12345})] public void ChunkSourceEvenly(int[] array) { - Assert.All(IdentityTransforms(), t => + Assert.All(CreateSources(array), source => { - IEnumerable source = t(array); - using IEnumerator chunks = source.Chunk(3).GetEnumerator(); chunks.MoveNext(); Assert.Equal(new[] { 9999, 0, 888 }, chunks.Current); @@ -73,10 +69,8 @@ public void ChunkSourceEvenly(int[] array) [InlineData(new[] {9999, 0, 888, -1, 66, -777, 1, 2})] public void ChunkSourceUnevenly(int[] array) { - Assert.All(IdentityTransforms(), t => + Assert.All(CreateSources(array), source => { - IEnumerable source = t(array); - using IEnumerator chunks = source.Chunk(3).GetEnumerator(); chunks.MoveNext(); Assert.Equal(new[] { 9999, 0, 888 }, chunks.Current); @@ -92,10 +86,8 @@ public void ChunkSourceUnevenly(int[] array) [InlineData(new[] {9999, 0})] public void ChunkSourceSmallerThanMaxSize(int[] array) { - Assert.All(IdentityTransforms(), t => + Assert.All(CreateSources(array), source => { - IEnumerable source = t(array); - using IEnumerator chunks = source.Chunk(3).GetEnumerator(); chunks.MoveNext(); Assert.Equal(new[] { 9999, 0 }, chunks.Current); @@ -107,10 +99,8 @@ public void ChunkSourceSmallerThanMaxSize(int[] array) [InlineData(new int[0])] public void EmptySourceYieldsNoChunks(int[] array) { - Assert.All(IdentityTransforms(), t => + Assert.All(CreateSources(array), source => { - IEnumerable source = t(array); - using IEnumerator chunks = source.Chunk(3).GetEnumerator(); Assert.False(chunks.MoveNext()); }); diff --git a/src/libraries/System.Linq/tests/ConcatTests.cs b/src/libraries/System.Linq/tests/ConcatTests.cs index 544027450d80c2..4069bbdf5de5a4 100644 --- a/src/libraries/System.Linq/tests/ConcatTests.cs +++ b/src/libraries/System.Linq/tests/ConcatTests.cs @@ -31,8 +31,8 @@ private static void SameResultsWithQueryAndRepeatCallsWorker(IEnumerable f first = from item in first select item; second = from item in second select item; - VerifyEqualsWorker(first.Concat(second), first.Concat(second)); - VerifyEqualsWorker(second.Concat(first), second.Concat(first)); + Assert.Equal(first.Concat(second), first.Concat(second)); + Assert.Equal(second.Concat(first), second.Concat(first)); } [Theory] @@ -41,8 +41,8 @@ private static void SameResultsWithQueryAndRepeatCallsWorker(IEnumerable f [InlineData(new int[] { 2, 3, 5, 9 }, new int[] { 8, 10 }, new int[] { 2, 3, 5, 9, 8, 10 })] // Neither side is empty public void PossiblyEmptyInputs(IEnumerable first, IEnumerable second, IEnumerable expected) { - VerifyEqualsWorker(expected, first.Concat(second)); - VerifyEqualsWorker(expected.Skip(first.Count()).Concat(expected.Take(first.Count())), second.Concat(first)); // Swap the inputs around + Assert.Equal(expected, first.Concat(second)); + Assert.Equal(expected.Skip(first.Count()).Concat(expected.Take(first.Count())), second.Concat(first)); // Swap the inputs around } [Fact] @@ -80,7 +80,7 @@ public void SecondNull() public void VerifyEquals(IEnumerable expected, IEnumerable actual) { // workaround: xUnit type inference doesn't work if the input type is not T (like IEnumerable) - VerifyEqualsWorker(expected, actual); + Assert.Equal(expected, actual); } [Theory] @@ -133,23 +133,6 @@ public void First_Last_ElementAt(IEnumerable _, IEnumerable actual) } } - private static void VerifyEqualsWorker(IEnumerable expected, IEnumerable actual) - { - // Returns a list of functions that, when applied to enumerable, should return - // another one that has equivalent contents. - var identityTransforms = IdentityTransforms(); - - // We run the transforms N^2 times, by testing all transforms - // of expected against all transforms of actual. - foreach (var outTransform in identityTransforms) - { - foreach (var inTransform in identityTransforms) - { - Assert.Equal(outTransform(expected), inTransform(actual)); - } - } - } - public static IEnumerable ArraySourcesData() => GenerateSourcesData(outerTransform: e => e.ToArray()); public static IEnumerable SelectArraySourcesData() => GenerateSourcesData(outerTransform: e => e.Select(i => i).ToArray()); @@ -292,7 +275,7 @@ public void ManyConcats(IEnumerable> sources) } Assert.Equal(sources.Sum(s => s.Count()), concatee.Count()); - VerifyEqualsWorker(sources.SelectMany(s => s), concatee); + Assert.Equal(sources.SelectMany(s => s), concatee); } } diff --git a/src/libraries/System.Linq/tests/CountTests.cs b/src/libraries/System.Linq/tests/CountTests.cs index 5b0730163721db..2937f116367f71 100644 --- a/src/libraries/System.Linq/tests/CountTests.cs +++ b/src/libraries/System.Linq/tests/CountTests.cs @@ -99,9 +99,9 @@ public void RunOnce(int count, IEnumerable enumerable) private static IEnumerable EnumerateCollectionTypesAndCounts(int count, IEnumerable enumerable) { - foreach (var transform in IdentityTransforms()) + foreach (IEnumerable source in CreateSources(enumerable)) { - yield return new object[] { count, transform(enumerable) }; + yield return [count, source]; } } diff --git a/src/libraries/System.Linq/tests/EnumerableTests.cs b/src/libraries/System.Linq/tests/EnumerableTests.cs index d28ace92a4026b..66bc25861e080e 100644 --- a/src/libraries/System.Linq/tests/EnumerableTests.cs +++ b/src/libraries/System.Linq/tests/EnumerableTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using Xunit; +using Xunit.Sdk; namespace System.Linq.Tests { @@ -243,6 +244,7 @@ protected static IEnumerable FlipIsCollection(IEnumerable source) { return source is ICollection ? ForceNotCollection(source) : new List(source); } + protected static T[] Repeat(Func factory, int count) { T[] results = new T[count]; @@ -316,26 +318,83 @@ protected static IEnumerable> CreateSources(IEnumerable sou } } - protected static List, IEnumerable>> IdentityTransforms() + protected static IEnumerable, IEnumerable>> IdentityTransforms() { - // All of these transforms should take an enumerable and produce - // another enumerable with the same contents. - return new List, IEnumerable>> + // Various collection types all representing the same source. + List, IEnumerable>> sources = + [ + e => e, // original + e => e.ToArray(), // T[] + e => e.ToList(), // List + e => new ReadOnlyCollection(e.ToArray()), // IList that's not List/T[] + e => new TestCollection(e.ToArray()), // ICollection that's not IList + e => new TestReadOnlyCollection(e.ToArray()), // IReadOnlyCollection that's not ICollection + e => ForceNotCollection(e), // IEnumerable with no other interfaces + ]; + if (typeof(T) == typeof(char)) { - e => e, - e => e.ToArray(), - e => e.ToList(), - e => e.ToList().Take(int.MaxValue), + sources.Add(e => (IEnumerable)(object)string.Concat((IEnumerable)(object)e)); // string + } + + // Various transforms that all yield the same elements as the source. + List, IEnumerable>> transforms = + [ + // Append + e => + { + T[] values = e.ToArray(); + return values.Length == 0 ? [] : values[0..^1].Append(values[^1]); + }, + + // Concat + e => e.Concat(ForceNotCollection([])), + e => ForceNotCollection([]).Concat(e), + + // Prepend + e => + { + T[] values = e.ToArray(); + return values.Length == 0 ? [] : values[1..].Prepend(values[0]); + }, + + // Reverse + e => e.Reverse().Reverse(), + + // Select e => e.Select(i => i), - e => e.Select(i => i).Take(int.MaxValue), - e => e.Select(i => i).Where(i => true), + + // SelectMany + e => e.SelectMany(i => [i]), + + // Take + e => e.Take(int.MaxValue), + e => e.TakeLast(int.MaxValue), + e => e.TakeWhile(i => true), + + // Skip + e => e.SkipWhile(i => false), + + // Where e => e.Where(i => true), - e => e.Concat(Array.Empty()), - e => e.Concat(ForceNotCollection(Array.Empty())), - e => ForceNotCollection(e), - e => ForceNotCollection(e).Skip(0), - e => new ReadOnlyCollection(e.ToArray()), - }; + ]; + + foreach (Func, IEnumerable> source in sources) + { + // Yield the source itself. + yield return source; + + foreach (Func, IEnumerable> transform in transforms) + { + // Yield a single transform on the source + yield return e => transform(source(e)); + + foreach (Func, IEnumerable> transform2 in transforms) + { + // Yield a second transform on the first transform on the source. + yield return e => transform2(transform(source(e))); + } + } + } } protected sealed class DelegateIterator : IEnumerable, IEnumerator diff --git a/src/libraries/System.Linq/tests/SelectManyTests.cs b/src/libraries/System.Linq/tests/SelectManyTests.cs index cb359f067848ba..98f2e37e54e32b 100644 --- a/src/libraries/System.Linq/tests/SelectManyTests.cs +++ b/src/libraries/System.Linq/tests/SelectManyTests.cs @@ -372,31 +372,23 @@ public void ForcedToEnumeratorDoesntEnumerateIndexedResultSel() Assert.False(en is not null && en.MoveNext()); } - [Theory] - [MemberData(nameof(ParameterizedTestsData))] - public void ParameterizedTests(IEnumerable source, Func> selector) + [Fact] + public void ParameterizedTests() { - Assert.All(CreateSources(source), source => + for (int i = 1; i <= 20; i++) { - var expected = source.Select(i => selector(i)).Aggregate((l, r) => l.Concat(r)); - var actual = source.SelectMany(selector); + Assert.All(CreateSources(Enumerable.Range(1, i)), source => + { + Func> selector = n => Enumerable.Range(i, n); - Assert.Equal(expected, actual); - Assert.Equal(expected.Count(), actual.Count()); // SelectMany may employ an optimized Count implementation. - Assert.Equal(expected.ToArray(), actual.ToArray()); - Assert.Equal(expected.ToList(), actual.ToList()); - }); - } + var expected = source.Select(i => selector(i)).Aggregate((l, r) => l.Concat(r)).ToArray(); + var actual = source.SelectMany(selector); - public static IEnumerable ParameterizedTestsData() - { - foreach (Func, IEnumerable> transform in IdentityTransforms()) - { - for (int i = 1; i <= 20; i++) - { - Func> selector = n => transform(Enumerable.Range(i, n)); - yield return new object[] { Enumerable.Range(1, i), selector }; - } + Assert.Equal(expected, actual); + Assert.Equal(expected.Length, actual.Count()); // SelectMany may employ an optimized Count implementation. + Assert.Equal(expected, actual.ToArray()); + Assert.Equal(expected, actual.ToList()); + }); } } diff --git a/src/libraries/System.Linq/tests/SingleOrDefaultTests.cs b/src/libraries/System.Linq/tests/SingleOrDefaultTests.cs index 8441f8a3c68a34..e04279bd00eac4 100644 --- a/src/libraries/System.Linq/tests/SingleOrDefaultTests.cs +++ b/src/libraries/System.Linq/tests/SingleOrDefaultTests.cs @@ -27,81 +27,33 @@ public void SameResultsRepeatCallsStringQuery() } [Fact] - public void EmptyIList() + public void Empty() { - int?[] source = { }; - int? expected = null; - - Assert.Equal(expected, source.SingleOrDefault()); - } - - [Fact] - public void EmptyIListDefault() - { - int?[] source = { }; - int expected = 5; - - Assert.Equal(expected, source.SingleOrDefault(5)); - } - - [Fact] - public void SingleElementIList() - { - int[] source = { 4 }; - int expected = 4; - - Assert.Equal(expected, source.SingleOrDefault()); + foreach (IEnumerable source in CreateSources([])) + { + Assert.Null(source.SingleOrDefault()); + Assert.Equal(5, source.SingleOrDefault(5)); + } } [Fact] - public void SingleElementIListDefault() + public void SingleElement() { - int[] source = { 4 }; - int expected = 4; - - Assert.Equal(expected, source.SingleOrDefault(5)); + foreach (IEnumerable source in CreateSources([4])) + { + Assert.Equal(4, source.SingleOrDefault()); + Assert.Equal(4, source.SingleOrDefault(5)); + } } [Fact] public void ManyElementIList() { - int[] source = { 4, 4, 4, 4, 4 }; - - Assert.Throws(() => source.SingleOrDefault()); - } - - [Fact] - public void ManyElementIListDefault() - { - int[] source = { 4, 4, 4, 4, 4 }; - - Assert.Throws(() => source.SingleOrDefault(5)); - } - - [Fact] - public void EmptyNotIList() - { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(0, 0); - int expected = default(int); - - Assert.Equal(expected, source.SingleOrDefault()); - } - - [Fact] - public void SingleElementNotIList() - { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(-5, 1); - int expected = -5; - - Assert.Equal(expected, source.SingleOrDefault()); - } - - [Fact] - public void ManyElementNotIList() - { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(3, 5); - - Assert.Throws(() => source.SingleOrDefault()); + foreach (IEnumerable source in CreateSources([4, 4, 4, 4, 4])) + { + Assert.Throws(() => source.SingleOrDefault()); + Assert.Throws(() => source.SingleOrDefault(4)); + } } [Fact] diff --git a/src/libraries/System.Linq/tests/SingleTests.cs b/src/libraries/System.Linq/tests/SingleTests.cs index 09e49daae1c099..21028511505289 100644 --- a/src/libraries/System.Linq/tests/SingleTests.cs +++ b/src/libraries/System.Linq/tests/SingleTests.cs @@ -37,53 +37,31 @@ public void SameResultsRepeatCallsIntQueryWithZero() } [Fact] - public void EmptyIList() + public void Empty() { - int[] source = { }; - - Assert.Throws(() => source.Single()); + foreach (IEnumerable source in CreateSources([])) + { + Assert.Throws(() => source.Single()); + } } [Fact] - public void SingleElementIList() + public void SingleElement() { - int[] source = { 4 }; int expected = 4; - - Assert.Equal(expected, source.Single()); - } - - [Fact] - public void ManyElementIList() - { - int[] source = { 4, 4, 4, 4, 4 }; - - Assert.Throws(() => source.Single()); - } - - [Fact] - public void EmptyNotIList() - { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(0, 0); - - Assert.Throws(() => source.Single()); - } - - [Fact] - public void SingleElementNotIList() - { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(-5, 1); - int expected = -5; - - Assert.Equal(expected, source.Single()); + foreach (IEnumerable source in CreateSources([4])) + { + Assert.Equal(expected, source.Single()); + } } [Fact] - public void ManyElementNotIList() + public void ManyElement() { - IEnumerable source = RepeatedNumberGuaranteedNotCollectionType(3, 5); - - Assert.Throws(() => source.Single()); + foreach (IEnumerable source in CreateSources([4, 4, 4, 4, 4])) + { + Assert.Throws(() => source.Single()); + } } [Fact] diff --git a/src/libraries/System.Linq/tests/SkipLastTests.cs b/src/libraries/System.Linq/tests/SkipLastTests.cs index c4770410870d47..0a2080a1ad37af 100644 --- a/src/libraries/System.Linq/tests/SkipLastTests.cs +++ b/src/libraries/System.Linq/tests/SkipLastTests.cs @@ -19,25 +19,26 @@ public void SkipLastThrowsOnNull() [MemberData(nameof(EnumerableData), MemberType = typeof(SkipTakeData))] public void SkipLast(IEnumerable source, int count) { - Assert.All(IdentityTransforms(), transform => - { - IEnumerable equivalent = transform(source); + int[] expected = source.Reverse().Skip(count).Reverse().ToArray(); - IEnumerable expected = equivalent.Reverse().Skip(count).Reverse(); - IEnumerable actual = equivalent.SkipLast(count); + Assert.All(CreateSources(source), source => + { + IEnumerable actual = source.SkipLast(count); Assert.Equal(expected, actual); - Assert.Equal(expected.Count(), actual.Count()); + + Assert.Equal(expected.Length, actual.Count()); Assert.Equal(expected, actual.ToArray()); Assert.Equal(expected, actual.ToList()); - Assert.Equal(expected.FirstOrDefault(), actual.FirstOrDefault()); Assert.Equal(expected.LastOrDefault(), actual.LastOrDefault()); - Assert.All(Enumerable.Range(0, expected.Count()), index => + if (expected.Length > 0) { - Assert.Equal(expected.ElementAt(index), actual.ElementAt(index)); - }); + Assert.Equal(expected[0], actual.ElementAt(0)); + Assert.Equal(expected[^1], actual.ElementAt(expected.Length - 1)); + Assert.Equal(expected[expected.Length / 2], actual.ElementAt(expected.Length / 2)); + } Assert.Equal(0, actual.ElementAtOrDefault(-1)); Assert.Equal(0, actual.ElementAtOrDefault(actual.Count())); diff --git a/src/libraries/System.Linq/tests/SkipTests.cs b/src/libraries/System.Linq/tests/SkipTests.cs index cf4d16b1309907..226c8f6b9152f8 100644 --- a/src/libraries/System.Linq/tests/SkipTests.cs +++ b/src/libraries/System.Linq/tests/SkipTests.cs @@ -10,12 +10,6 @@ namespace System.Linq.Tests { public class SkipTests : EnumerableTests { - private static IEnumerable GuaranteeNotIList(IEnumerable source) - { - foreach (T element in source) - yield return element; - } - [Fact] public void SkipSome() { @@ -87,139 +81,95 @@ public void SkipThrowsOnNullIList() [Fact] public void SkipOnEmpty() { - Assert.Equal(Enumerable.Empty(), GuaranteeNotIList(Enumerable.Empty()).Skip(0)); - Assert.Equal(Enumerable.Empty(), GuaranteeNotIList(Enumerable.Empty()).Skip(-1)); - Assert.Equal(Enumerable.Empty(), GuaranteeNotIList(Enumerable.Empty()).Skip(1)); - } + foreach (IEnumerable source in CreateSources([])) + { + Assert.Equal([], source.Skip(0)); + Assert.Equal([], source.Skip(-1)); + Assert.Equal([], source.Skip(1)); + } - [Fact] - public void SkipOnEmptyIList() - { - // Enumerable.Empty does return an IList, but not guaranteed as such - // by the spec. - Assert.Equal(Enumerable.Empty(), Enumerable.Empty().ToList().Skip(0)); - Assert.Equal(Enumerable.Empty(), Enumerable.Empty().ToList().Skip(-1)); - Assert.Equal(Enumerable.Empty(), Enumerable.Empty().ToList().Skip(1)); + foreach (IEnumerable source in CreateSources([])) + { + Assert.Equal([], source.Skip(0)); + Assert.Equal([], source.Skip(-1)); + Assert.Equal([], source.Skip(1)); + } } [Fact] public void SkipNegative() { - Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).Skip(-42)); - } - - [Fact] - public void SkipNegativeIList() - { - Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).ToList().Skip(-42)); + foreach (IEnumerable source in CreateSources(Enumerable.Range(0, 20))) + { + Assert.Equal(Enumerable.Range(0, 20), source.Skip(-42)); + } } [Fact] public void SameResultsRepeatCallsIntQuery() { - var q = GuaranteeNotIList(from x in new[] { 9999, 0, 888, -1, 66, -777, 1, 2, -12345 } - where x > int.MinValue - select x); - - Assert.Equal(q.Skip(0), q.Skip(0)); - } - - [Fact] - public void SameResultsRepeatCallsIntQueryIList() - { - var q = (from x in new[] { 9999, 0, 888, -1, 66, -777, 1, 2, -12345 } - where x > Int32.MinValue - select x).ToList(); + foreach (IEnumerable source in CreateSources([9999, 0, 888, -1, 66, -777, 1, 2, -12345])) + { + IEnumerable q = from x in source + where x > int.MinValue + select x; - Assert.Equal(q.Skip(0), q.Skip(0)); + Assert.Equal(q.Skip(0), q.Skip(0)); + } } [Fact] public void SameResultsRepeatCallsStringQuery() { - var q = GuaranteeNotIList(from x in new[] { "!@#$%^", "C", "AAA", "", "Calling Twice", "SoS", string.Empty } - where !string.IsNullOrEmpty(x) - select x); - - Assert.Equal(q.Skip(0), q.Skip(0)); - } - - [Fact] - public void SameResultsRepeatCallsStringQueryIList() - { - var q = (from x in new[] { "!@#$%^", "C", "AAA", "", "Calling Twice", "SoS", String.Empty } - where !String.IsNullOrEmpty(x) - select x).ToList(); + foreach (IEnumerable source in CreateSources(["!@#$%^", "C", "AAA", "", "Calling Twice", "SoS", string.Empty])) + { + IEnumerable q = from x in source + where !string.IsNullOrEmpty(x) + select x; - Assert.Equal(q.Skip(0), q.Skip(0)); + Assert.Equal(q.Skip(0), q.Skip(0)); + } } [Fact] public void SkipOne() { - int?[] source = { 3, 100, 4, null, 10 }; - int?[] expected = { 100, 4, null, 10 }; - - Assert.Equal(expected, source.Skip(1)); - } - - [Fact] - public void SkipOneNotIList() - { - int?[] source = { 3, 100, 4, null, 10 }; - int?[] expected = { 100, 4, null, 10 }; - - Assert.Equal(expected, GuaranteeNotIList(source).Skip(1)); + int?[] expected = [100, 4, null, 10]; + foreach (IEnumerable source in CreateSources([3, 100, 4, null, 10])) + { + Assert.Equal(expected, source.Skip(1)); + } } [Fact] public void SkipAllButOne() { - int?[] source = { 3, 100, null, 4, 10 }; - int?[] expected = { 10 }; - - Assert.Equal(expected, source.Skip(source.Length - 1)); - } - - [Fact] - public void SkipAllButOneNotIList() - { - int?[] source = { 3, 100, null, 4, 10 }; - int?[] expected = { 10 }; - - Assert.Equal(expected, GuaranteeNotIList(source.Skip(source.Length - 1))); + int?[] expected = [10]; + foreach (IEnumerable source in CreateSources([3, 100, 4, null, 10])) + { + Assert.Equal(expected, source.Skip(4)); + } } [Fact] public void SkipOneMoreThanAll() { - int[] source = { 3, 100, 4, 10 }; - Assert.Empty(source.Skip(source.Length + 1)); - } - - [Fact] - public void SkipOneMoreThanAllNotIList() - { - int[] source = { 3, 100, 4, 10 }; - Assert.Empty(GuaranteeNotIList(source).Skip(source.Length + 1)); + foreach (IEnumerable source in CreateSources([3, 100, 4, 10])) + { + Assert.Empty(source.Skip(5)); + } } [Fact] public void ForcedToEnumeratorDoesntEnumerate() { - var iterator = NumberRangeGuaranteedNotCollectionType(0, 3).Skip(2); - // Don't insist on this behaviour, but check it's correct if it happens - var en = iterator as IEnumerator; - Assert.False(en is not null && en.MoveNext()); - } - - [Fact] - public void ForcedToEnumeratorDoesntEnumerateIList() - { - var iterator = (new[] { 0, 1, 2 }).Skip(2); - // Don't insist on this behaviour, but check it's correct if it happens - var en = iterator as IEnumerator; - Assert.False(en is not null && en.MoveNext()); + foreach (IEnumerable source in CreateSources(Enumerable.Range(0, 3))) + { + // Don't insist on this behaviour, but check it's correct if it happens + IEnumerable iterator = source.Skip(2); + var en = iterator as IEnumerator; + Assert.False(en is not null && en.MoveNext()); + } } [Fact] @@ -232,243 +182,150 @@ public void Count() [Fact] public void FollowWithTake() { - var source = new[] { 5, 6, 7, 8 }; - var expected = new[] { 6, 7 }; - Assert.Equal(expected, source.Skip(1).Take(2)); - } - - [Fact] - public void FollowWithTakeNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(5, 4); - var expected = new[] { 6, 7 }; - Assert.Equal(expected, source.Skip(1).Take(2)); + int[] expected = [6, 7]; + foreach (IEnumerable source in CreateSources(Enumerable.Range(5, 4))) + { + Assert.Equal(expected, source.Skip(1).Take(2)); + } } [Fact] public void FollowWithTakeThenMassiveTake() { - var source = new[] { 5, 6, 7, 8 }; - var expected = new[] { 7 }; - Assert.Equal(expected, source.Skip(2).Take(1).Take(int.MaxValue)); - } - [Fact] - public void FollowWithTakeThenMassiveTakeNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(5, 4); - var expected = new[] { 7 }; - Assert.Equal(expected, source.Skip(2).Take(1).Take(int.MaxValue)); + int[] expected = [7]; + foreach (IEnumerable source in CreateSources([5, 6, 7, 8])) + { + Assert.Equal(expected, source.Skip(2).Take(1).Take(int.MaxValue)); + } } [Fact] public void FollowWithSkip() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; - var expected = new[] { 4, 5, 6 }; - Assert.Equal(expected, source.Skip(1).Skip(2).Skip(-4)); - } - - [Fact] - public void FollowWithSkipNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(1, 6); - var expected = new[] { 4, 5, 6 }; - Assert.Equal(expected, source.Skip(1).Skip(2).Skip(-4)); + int[] expected = [4, 5, 6]; + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + Assert.Equal(expected, source.Skip(1).Skip(2).Skip(-4)); + } } [Fact] public void ElementAt() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; - var remaining = source.Skip(2); - Assert.Equal(3, remaining.ElementAt(0)); - Assert.Equal(4, remaining.ElementAt(1)); - Assert.Equal(6, remaining.ElementAt(3)); - AssertExtensions.Throws("index", () => remaining.ElementAt(-1)); - AssertExtensions.Throws("index", () => remaining.ElementAt(4)); - } - - [Fact] - public void ElementAtNotIList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5, 6 }); - var remaining = source.Skip(2); - Assert.Equal(3, remaining.ElementAt(0)); - Assert.Equal(4, remaining.ElementAt(1)); - Assert.Equal(6, remaining.ElementAt(3)); - AssertExtensions.Throws("index", () => remaining.ElementAt(-1)); - AssertExtensions.Throws("index", () => remaining.ElementAt(4)); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + IEnumerable remaining = source.Skip(2); + Assert.Equal(3, remaining.ElementAt(0)); + Assert.Equal(4, remaining.ElementAt(1)); + Assert.Equal(6, remaining.ElementAt(3)); + AssertExtensions.Throws("index", () => remaining.ElementAt(-1)); + AssertExtensions.Throws("index", () => remaining.ElementAt(4)); + } } [Fact] public void ElementAtOrDefault() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; - var remaining = source.Skip(2); - Assert.Equal(3, remaining.ElementAtOrDefault(0)); - Assert.Equal(4, remaining.ElementAtOrDefault(1)); - Assert.Equal(6, remaining.ElementAtOrDefault(3)); - Assert.Equal(0, remaining.ElementAtOrDefault(-1)); - Assert.Equal(0, remaining.ElementAtOrDefault(4)); - } - - [Fact] - public void ElementAtOrDefaultNotIList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5, 6 }); - var remaining = source.Skip(2); - Assert.Equal(3, remaining.ElementAtOrDefault(0)); - Assert.Equal(4, remaining.ElementAtOrDefault(1)); - Assert.Equal(6, remaining.ElementAtOrDefault(3)); - Assert.Equal(0, remaining.ElementAtOrDefault(-1)); - Assert.Equal(0, remaining.ElementAtOrDefault(4)); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + IEnumerable remaining = source.Skip(2); + Assert.Equal(3, remaining.ElementAtOrDefault(0)); + Assert.Equal(4, remaining.ElementAtOrDefault(1)); + Assert.Equal(6, remaining.ElementAtOrDefault(3)); + Assert.Equal(0, remaining.ElementAtOrDefault(-1)); + Assert.Equal(0, remaining.ElementAtOrDefault(4)); + } } [Fact] public void First() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Skip(0).First()); - Assert.Equal(3, source.Skip(2).First()); - Assert.Equal(5, source.Skip(4).First()); - Assert.Throws(() => source.Skip(5).First()); - } - - [Fact] - public void FirstNotIList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Skip(0).First()); - Assert.Equal(3, source.Skip(2).First()); - Assert.Equal(5, source.Skip(4).First()); - Assert.Throws(() => source.Skip(5).First()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Skip(0).First()); + Assert.Equal(3, source.Skip(2).First()); + Assert.Equal(5, source.Skip(4).First()); + Assert.Throws(() => source.Skip(5).First()); + } } [Fact] public void FirstOrDefault() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Skip(0).FirstOrDefault()); - Assert.Equal(3, source.Skip(2).FirstOrDefault()); - Assert.Equal(5, source.Skip(4).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).FirstOrDefault()); - } - - [Fact] - public void FirstOrDefaultNotIList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Skip(0).FirstOrDefault()); - Assert.Equal(3, source.Skip(2).FirstOrDefault()); - Assert.Equal(5, source.Skip(4).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).FirstOrDefault()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Skip(0).FirstOrDefault()); + Assert.Equal(3, source.Skip(2).FirstOrDefault()); + Assert.Equal(5, source.Skip(4).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).FirstOrDefault()); + } } [Fact] public void Last() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(5, source.Skip(0).Last()); - Assert.Equal(5, source.Skip(1).Last()); - Assert.Equal(5, source.Skip(4).Last()); - Assert.Throws(() => source.Skip(5).Last()); - } - - [Fact] - public void LastNotList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(5, source.Skip(0).Last()); - Assert.Equal(5, source.Skip(1).Last()); - Assert.Equal(5, source.Skip(4).Last()); - Assert.Throws(() => source.Skip(5).Last()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(5, source.Skip(0).Last()); + Assert.Equal(5, source.Skip(1).Last()); + Assert.Equal(5, source.Skip(4).Last()); + Assert.Throws(() => source.Skip(5).Last()); + } } [Fact] public void LastOrDefault() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(5, source.Skip(0).LastOrDefault()); - Assert.Equal(5, source.Skip(1).LastOrDefault()); - Assert.Equal(5, source.Skip(4).LastOrDefault()); - Assert.Equal(0, source.Skip(5).LastOrDefault()); - } - - [Fact] - public void LastOrDefaultNotList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(5, source.Skip(0).LastOrDefault()); - Assert.Equal(5, source.Skip(1).LastOrDefault()); - Assert.Equal(5, source.Skip(4).LastOrDefault()); - Assert.Equal(0, source.Skip(5).LastOrDefault()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(5, source.Skip(0).LastOrDefault()); + Assert.Equal(5, source.Skip(1).LastOrDefault()); + Assert.Equal(5, source.Skip(4).LastOrDefault()); + Assert.Equal(0, source.Skip(5).LastOrDefault()); + } } [Fact] public void ToArray() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToArray()); - Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToArray()); - Assert.Equal(5, source.Skip(4).ToArray().Single()); - Assert.Empty(source.Skip(5).ToArray()); - Assert.Empty(source.Skip(40).ToArray()); - } - - [Fact] - public void ToArrayNotList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToArray()); - Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToArray()); - Assert.Equal(5, source.Skip(4).ToArray().Single()); - Assert.Empty(source.Skip(5).ToArray()); - Assert.Empty(source.Skip(40).ToArray()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToArray()); + Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToArray()); + Assert.Equal(5, source.Skip(4).ToArray().Single()); + Assert.Empty(source.Skip(5).ToArray()); + Assert.Empty(source.Skip(40).ToArray()); + } } [Fact] public void ToList() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToList()); - Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToList()); - Assert.Equal(5, source.Skip(4).ToList().Single()); - Assert.Empty(source.Skip(5).ToList()); - Assert.Empty(source.Skip(40).ToList()); - } - - [Fact] - public void ToListNotList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToList()); - Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToList()); - Assert.Equal(5, source.Skip(4).ToList().Single()); - Assert.Empty(source.Skip(5).ToList()); - Assert.Empty(source.Skip(40).ToList()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToList()); + Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToList()); + Assert.Equal(5, source.Skip(4).ToList().Single()); + Assert.Empty(source.Skip(5).ToList()); + Assert.Empty(source.Skip(40).ToList()); + } } [Fact] public void RepeatEnumerating() { - var source = new[] { 1, 2, 3, 4, 5 }; - var remaining = source.Skip(1); - Assert.Equal(remaining, remaining); - } - - [Fact] - public void RepeatEnumeratingNotList() - { - var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 }); - var remaining = source.Skip(1); - Assert.Equal(remaining, remaining); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + IEnumerable remaining = source.Skip(1); + Assert.Equal(remaining, remaining); + } } [Fact] public void LazySkipMoreThan32Bits() { - var range = NumberRangeGuaranteedNotCollectionType(1, 100); - var skipped = range.Skip(50).Skip(int.MaxValue); // Could cause an integer overflow. + IEnumerable range = NumberRangeGuaranteedNotCollectionType(1, 100); + IEnumerable skipped = range.Skip(50).Skip(int.MaxValue); // Could cause an integer overflow. Assert.Empty(skipped); Assert.Equal(0, skipped.Count()); Assert.Empty(skipped.ToArray()); @@ -489,7 +346,7 @@ public void IteratorStateShouldNotChangeIfNumberOfElementsIsUnbounded() // so that it does not overflow to a negative number and enumeration does not // stop prematurely. - var iterator = new FastInfiniteEnumerator().Skip(1).GetEnumerator(); + using IEnumerator iterator = new FastInfiniteEnumerator().Skip(1).GetEnumerator(); iterator.MoveNext(); // Make sure the underlying enumerator has been initialized. FieldInfo state = iterator.GetType().GetTypeInfo() diff --git a/src/libraries/System.Linq/tests/TakeLastTests.cs b/src/libraries/System.Linq/tests/TakeLastTests.cs index b39d59e94263a6..4d011d50cfd63c 100644 --- a/src/libraries/System.Linq/tests/TakeLastTests.cs +++ b/src/libraries/System.Linq/tests/TakeLastTests.cs @@ -19,25 +19,26 @@ public void SkipLastThrowsOnNull() [MemberData(nameof(EnumerableData), MemberType = typeof(SkipTakeData))] public void TakeLast(IEnumerable source, int count) { - Assert.All(IdentityTransforms(), transform => - { - IEnumerable equivalent = transform(source); + int[] expected = source.Reverse().Take(count).Reverse().ToArray(); - IEnumerable expected = equivalent.Reverse().Take(count).Reverse(); - IEnumerable actual = equivalent.TakeLast(count); + Assert.All(CreateSources(source), source => + { + IEnumerable actual = source.TakeLast(count); Assert.Equal(expected, actual); - Assert.Equal(expected.Count(), actual.Count()); + + Assert.Equal(expected.Length, actual.Count()); Assert.Equal(expected, actual.ToArray()); Assert.Equal(expected, actual.ToList()); - Assert.Equal(expected.FirstOrDefault(), actual.FirstOrDefault()); Assert.Equal(expected.LastOrDefault(), actual.LastOrDefault()); - Assert.All(Enumerable.Range(0, expected.Count()), index => + if (expected.Length > 0) { - Assert.Equal(expected.ElementAt(index), actual.ElementAt(index)); - }); + Assert.Equal(expected[0], actual.ElementAt(0)); + Assert.Equal(expected[^1], actual.ElementAt(expected.Length - 1)); + Assert.Equal(expected[expected.Length / 2], actual.ElementAt(expected.Length / 2)); + } Assert.Equal(0, actual.ElementAtOrDefault(-1)); Assert.Equal(0, actual.ElementAtOrDefault(actual.Count())); diff --git a/src/libraries/System.Linq/tests/TakeTests.cs b/src/libraries/System.Linq/tests/TakeTests.cs index d9408a157124bf..c39c9357ea7c57 100644 --- a/src/libraries/System.Linq/tests/TakeTests.cs +++ b/src/libraries/System.Linq/tests/TakeTests.cs @@ -72,135 +72,85 @@ public void SameResultsRepeatCallsStringQueryIList() [Fact] public void SourceEmptyCountPositive() { - var source = new int[] { }; - Assert.Empty(source.Take(5)); - - Assert.Empty(source.Take(0..5)); - Assert.Empty(source.Take(^5..5)); - Assert.Empty(source.Take(0..^0)); - Assert.Empty(source.Take(^5..^0)); - } - - [Fact] - public void SourceEmptyCountPositiveNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(0, 0); - Assert.Empty(source.Take(5)); + foreach (IEnumerable source in CreateSources([])) + { + Assert.Empty(source.Take(5)); - Assert.Empty(source.Take(0..5)); - Assert.Empty(source.Take(^5..5)); - Assert.Empty(source.Take(0..^0)); - Assert.Empty(source.Take(^5..^0)); + Assert.Empty(source.Take(0..5)); + Assert.Empty(source.Take(^5..5)); + Assert.Empty(source.Take(0..^0)); + Assert.Empty(source.Take(^5..^0)); + } } [Fact] public void SourceNonEmptyCountNegative() { - var source = new[] { 2, 5, 9, 1 }; - Assert.Empty(source.Take(-5)); - - Assert.Empty(source.Take(^9..0)); - } - - [Fact] - public void SourceNonEmptyCountNegativeNotIList() - { - var source = ForceNotCollection(new[] { 2, 5, 9, 1 }); - Assert.Empty(source.Take(-5)); - - Assert.Empty(source.Take(^9..0)); + foreach (IEnumerable source in CreateSources([2, 5, 9, 1])) + { + Assert.Empty(source.Take(-5)); + Assert.Empty(source.Take(^9..0)); + } } [Fact] public void SourceNonEmptyCountZero() { - var source = new[] { 2, 5, 9, 1 }; - Assert.Empty(source.Take(0)); - - Assert.Empty(source.Take(0..0)); - Assert.Empty(source.Take(^4..0)); - Assert.Empty(source.Take(0..^4)); - Assert.Empty(source.Take(^4..^4)); - } - - [Fact] - public void SourceNonEmptyCountZeroNotIList() - { - var source = ForceNotCollection(new[] { 2, 5, 9, 1 }); - Assert.Empty(source.Take(0)); + foreach (IEnumerable source in CreateSources([2, 5, 9, 1])) + { + Assert.Empty(source.Take(0)); - Assert.Empty(source.Take(0..0)); - Assert.Empty(source.Take(^4..0)); - Assert.Empty(source.Take(0..^4)); - Assert.Empty(source.Take(^4..^4)); + Assert.Empty(source.Take(0..0)); + Assert.Empty(source.Take(^4..0)); + Assert.Empty(source.Take(0..^4)); + Assert.Empty(source.Take(^4..^4)); + } } [Fact] public void SourceNonEmptyCountOne() { - var source = new[] { 2, 5, 9, 1 }; - int[] expected = { 2 }; + int[] expected = [2]; - Assert.Equal(expected, source.Take(1)); - - Assert.Equal(expected, source.Take(0..1)); - Assert.Equal(expected, source.Take(^4..1)); - Assert.Equal(expected, source.Take(0..^3)); - Assert.Equal(expected, source.Take(^4..^3)); - } - - [Fact] - public void SourceNonEmptyCountOneNotIList() - { - var source = ForceNotCollection(new[] { 2, 5, 9, 1 }); - int[] expected = { 2 }; - - Assert.Equal(expected, source.Take(1)); + foreach (IEnumerable source in CreateSources([2, 5, 9, 1])) + { + Assert.Equal(expected, source.Take(1)); - Assert.Equal(expected, source.Take(0..1)); - Assert.Equal(expected, source.Take(^4..1)); - Assert.Equal(expected, source.Take(0..^3)); - Assert.Equal(expected, source.Take(^4..^3)); + Assert.Equal(expected, source.Take(0..1)); + Assert.Equal(expected, source.Take(^4..1)); + Assert.Equal(expected, source.Take(0..^3)); + Assert.Equal(expected, source.Take(^4..^3)); + } } [Fact] public void SourceNonEmptyTakeAllExactly() { - var source = new[] { 2, 5, 9, 1 }; - - Assert.Equal(source, source.Take(source.Length)); - - Assert.Equal(source, source.Take(0..source.Length)); - Assert.Equal(source, source.Take(^source.Length..source.Length)); - Assert.Equal(source, source.Take(0..^0)); - Assert.Equal(source, source.Take(^source.Length..^0)); - } - - [Fact] - public void SourceNonEmptyTakeAllExactlyNotIList() - { - var source = ForceNotCollection(new[] { 2, 5, 9, 1 }); - - Assert.Equal(source, source.Take(source.Count())); + foreach (IEnumerable source in CreateSources([2, 5, 9, 1])) + { + Assert.Equal(source, source.Take(4)); - Assert.Equal(source, source.Take(0..source.Count())); - Assert.Equal(source, source.Take(^source.Count()..source.Count())); - Assert.Equal(source, source.Take(0..^0)); - Assert.Equal(source, source.Take(^source.Count()..^0)); + Assert.Equal(source, source.Take(0..4)); + Assert.Equal(source, source.Take(^4..4)); + Assert.Equal(source, source.Take(0..^0)); + Assert.Equal(source, source.Take(^4..^0)); + } } [Fact] public void SourceNonEmptyTakeAllButOne() { - var source = new[] { 2, 5, 9, 1 }; - int[] expected = { 2, 5, 9 }; + int[] expected = [2, 5, 9]; - Assert.Equal(expected, source.Take(3)); + foreach (IEnumerable source in CreateSources([2, 5, 9, 1])) + { + Assert.Equal(expected, source.Take(3)); - Assert.Equal(expected, source.Take(0..3)); - Assert.Equal(expected, source.Take(^4..3)); - Assert.Equal(expected, source.Take(0..^1)); - Assert.Equal(expected, source.Take(^4..^1)); + Assert.Equal(expected, source.Take(0..3)); + Assert.Equal(expected, source.Take(^4..3)); + Assert.Equal(expected, source.Take(0..^1)); + Assert.Equal(expected, source.Take(^4..^1)); + } } [Fact] @@ -217,40 +167,16 @@ public void RunOnce() Assert.Equal(expected, source.RunOnce().Take(^4..^1)); } - [Fact] - public void SourceNonEmptyTakeAllButOneNotIList() - { - var source = ForceNotCollection(new[] { 2, 5, 9, 1 }); - int[] expected = { 2, 5, 9 }; - - Assert.Equal(expected, source.RunOnce().Take(3)); - - Assert.Equal(expected, source.RunOnce().Take(0..3)); - Assert.Equal(expected, source.RunOnce().Take(^4..3)); - Assert.Equal(expected, source.RunOnce().Take(0..^1)); - Assert.Equal(expected, source.RunOnce().Take(^4..^1)); - } - [Fact] public void SourceNonEmptyTakeExcessive() { - var source = new int?[] { 2, 5, null, 9, 1 }; - - Assert.Equal(source, source.Take(source.Length + 1)); - - Assert.Equal(source, source.Take(0..(source.Length + 1))); - Assert.Equal(source, source.Take(^(source.Length + 1)..(source.Length + 1))); - } - - [Fact] - public void SourceNonEmptyTakeExcessiveNotIList() - { - var source = ForceNotCollection(new int?[] { 2, 5, null, 9, 1 }); - - Assert.Equal(source, source.Take(source.Count() + 1)); + foreach (IEnumerable source in CreateSources([2, 5, null, 9, 1])) + { + Assert.Equal(source, source.Take(5)); - Assert.Equal(source, source.Take(0..(source.Count() + 1))); - Assert.Equal(source, source.Take(^(source.Count() + 1)..(source.Count() + 1))); + Assert.Equal(source, source.Take(0..5)); + Assert.Equal(source, source.Take(^6..6)); + } } [Fact] @@ -342,741 +268,405 @@ public void ForcedToEnumeratorDoesntEnumerateIList() [Fact] public void FollowWithTake() { - var source = new[] { 5, 6, 7, 8 }; var expected = new[] { 5, 6 }; - Assert.Equal(expected, source.Take(5).Take(3).Take(2).Take(40)); - Assert.Equal(expected, source.Take(0..5).Take(0..3).Take(0..2).Take(0..40)); - Assert.Equal(expected, source.Take(^4..5).Take(^4..3).Take(^3..2).Take(^2..40)); - Assert.Equal(expected, source.Take(0..^0).Take(0..^1).Take(0..^1).Take(0..^0)); - Assert.Equal(expected, source.Take(^4..^0).Take(^4..^1).Take(^3..^1).Take(^2..^0)); - } - - [Fact] - public void FollowWithTakeNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(5, 4); - var expected = new[] { 5, 6 }; - Assert.Equal(expected, source.Take(5).Take(3).Take(2)); + foreach (IEnumerable source in CreateSources([5, 6, 7, 8])) + { + Assert.Equal(expected, source.Take(5).Take(3).Take(2).Take(40)); - Assert.Equal(expected, source.Take(0..5).Take(0..3).Take(0..2)); - Assert.Equal(expected, source.Take(^4..5).Take(^4..3).Take(^3..2)); - Assert.Equal(expected, source.Take(0..^0).Take(0..^1).Take(0..^1)); - Assert.Equal(expected, source.Take(^4..^0).Take(^4..^1).Take(^3..^1)); + Assert.Equal(expected, source.Take(0..5).Take(0..3).Take(0..2).Take(0..40)); + Assert.Equal(expected, source.Take(^4..5).Take(^4..3).Take(^3..2).Take(^2..40)); + Assert.Equal(expected, source.Take(0..^0).Take(0..^1).Take(0..^1).Take(0..^0)); + Assert.Equal(expected, source.Take(^4..^0).Take(^4..^1).Take(^3..^1).Take(^2..^0)); + } } [Fact] public void FollowWithSkip() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; var expected = new[] { 3, 4, 5 }; - Assert.Equal(expected, source.Take(5).Skip(2).Skip(-4)); - - Assert.Equal(expected, source.Take(0..5).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(^6..5).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(0..^1).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(^6..^1).Skip(2).Skip(-4)); - } - [Fact] - public void FollowWithSkipNotIList() - { - var source = NumberRangeGuaranteedNotCollectionType(1, 6); - var expected = new[] { 3, 4, 5 }; - Assert.Equal(expected, source.Take(5).Skip(2).Skip(-4)); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + Assert.Equal(expected, source.Take(5).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(0..5).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(^6..5).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(0..^1).Skip(2).Skip(-4)); - Assert.Equal(expected, source.Take(^6..^1).Skip(2).Skip(-4)); + Assert.Equal(expected, source.Take(0..5).Skip(2).Skip(-4)); + Assert.Equal(expected, source.Take(^6..5).Skip(2).Skip(-4)); + Assert.Equal(expected, source.Take(0..^1).Skip(2).Skip(-4)); + Assert.Equal(expected, source.Take(^6..^1).Skip(2).Skip(-4)); + } } [Fact] public void ElementAt() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; - var taken0 = source.Take(3); - Assert.Equal(1, taken0.ElementAt(0)); - Assert.Equal(3, taken0.ElementAt(2)); - Assert.Throws("index", () => taken0.ElementAt(-1)); - Assert.Throws("index", () => taken0.ElementAt(3)); - - var taken1 = source.Take(0..3); - Assert.Equal(1, taken1.ElementAt(0)); - Assert.Equal(3, taken1.ElementAt(2)); - Assert.Throws("index", () => taken1.ElementAt(-1)); - Assert.Throws("index", () => taken1.ElementAt(3)); - - var taken2 = source.Take(^6..3); - Assert.Equal(1, taken2.ElementAt(0)); - Assert.Equal(3, taken2.ElementAt(2)); - Assert.Throws("index", () => taken2.ElementAt(-1)); - Assert.Throws("index", () => taken2.ElementAt(3)); - - var taken3 = source.Take(0..^3); - Assert.Equal(1, taken3.ElementAt(0)); - Assert.Equal(3, taken3.ElementAt(2)); - Assert.Throws("index", () => taken3.ElementAt(-1)); - Assert.Throws("index", () => taken3.ElementAt(3)); - - var taken4 = source.Take(^6..^3); - Assert.Equal(1, taken4.ElementAt(0)); - Assert.Equal(3, taken4.ElementAt(2)); - Assert.Throws("index", () => taken4.ElementAt(-1)); - Assert.Throws("index", () => taken4.ElementAt(3)); - } - - [Fact] - public void ElementAtNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5, 6 }); - var taken0 = source.Take(3); - Assert.Equal(1, taken0.ElementAt(0)); - Assert.Equal(3, taken0.ElementAt(2)); - Assert.Throws("index", () => taken0.ElementAt(-1)); - Assert.Throws("index", () => taken0.ElementAt(3)); - - var taken1 = source.Take(0..3); - Assert.Equal(1, taken1.ElementAt(0)); - Assert.Equal(3, taken1.ElementAt(2)); - Assert.Throws("index", () => taken1.ElementAt(-1)); - Assert.Throws("index", () => taken1.ElementAt(3)); - - var taken2 = source.Take(^6..3); - Assert.Equal(1, taken2.ElementAt(0)); - Assert.Equal(3, taken2.ElementAt(2)); - Assert.Throws("index", () => taken2.ElementAt(-1)); - Assert.Throws("index", () => taken2.ElementAt(3)); - - var taken3 = source.Take(0..^3); - Assert.Equal(1, taken3.ElementAt(0)); - Assert.Equal(3, taken3.ElementAt(2)); - Assert.Throws("index", () => taken3.ElementAt(-1)); - Assert.Throws("index", () => taken3.ElementAt(3)); - - var taken4 = source.Take(^6..^3); - Assert.Equal(1, taken4.ElementAt(0)); - Assert.Equal(3, taken4.ElementAt(2)); - Assert.Throws("index", () => taken4.ElementAt(-1)); - Assert.Throws("index", () => taken4.ElementAt(3)); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + var taken0 = source.Take(3); + Assert.Equal(1, taken0.ElementAt(0)); + Assert.Equal(3, taken0.ElementAt(2)); + Assert.Throws("index", () => taken0.ElementAt(-1)); + Assert.Throws("index", () => taken0.ElementAt(3)); + + var taken1 = source.Take(0..3); + Assert.Equal(1, taken1.ElementAt(0)); + Assert.Equal(3, taken1.ElementAt(2)); + Assert.Throws("index", () => taken1.ElementAt(-1)); + Assert.Throws("index", () => taken1.ElementAt(3)); + + var taken2 = source.Take(^6..3); + Assert.Equal(1, taken2.ElementAt(0)); + Assert.Equal(3, taken2.ElementAt(2)); + Assert.Throws("index", () => taken2.ElementAt(-1)); + Assert.Throws("index", () => taken2.ElementAt(3)); + + var taken3 = source.Take(0..^3); + Assert.Equal(1, taken3.ElementAt(0)); + Assert.Equal(3, taken3.ElementAt(2)); + Assert.Throws("index", () => taken3.ElementAt(-1)); + Assert.Throws("index", () => taken3.ElementAt(3)); + + var taken4 = source.Take(^6..^3); + Assert.Equal(1, taken4.ElementAt(0)); + Assert.Equal(3, taken4.ElementAt(2)); + Assert.Throws("index", () => taken4.ElementAt(-1)); + Assert.Throws("index", () => taken4.ElementAt(3)); + } } [Fact] public void ElementAtOrDefault() { - var source = new[] { 1, 2, 3, 4, 5, 6 }; - var taken0 = source.Take(3); - Assert.Equal(1, taken0.ElementAtOrDefault(0)); - Assert.Equal(3, taken0.ElementAtOrDefault(2)); - Assert.Equal(0, taken0.ElementAtOrDefault(-1)); - Assert.Equal(0, taken0.ElementAtOrDefault(3)); - - var taken1 = source.Take(0..3); - Assert.Equal(1, taken1.ElementAtOrDefault(0)); - Assert.Equal(3, taken1.ElementAtOrDefault(2)); - Assert.Equal(0, taken1.ElementAtOrDefault(-1)); - Assert.Equal(0, taken1.ElementAtOrDefault(3)); - - var taken2 = source.Take(^6..3); - Assert.Equal(1, taken2.ElementAtOrDefault(0)); - Assert.Equal(3, taken2.ElementAtOrDefault(2)); - Assert.Equal(0, taken2.ElementAtOrDefault(-1)); - Assert.Equal(0, taken2.ElementAtOrDefault(3)); - - var taken3 = source.Take(0..^3); - Assert.Equal(1, taken3.ElementAtOrDefault(0)); - Assert.Equal(3, taken3.ElementAtOrDefault(2)); - Assert.Equal(0, taken3.ElementAtOrDefault(-1)); - Assert.Equal(0, taken3.ElementAtOrDefault(3)); - - var taken4 = source.Take(^6..^3); - Assert.Equal(1, taken4.ElementAtOrDefault(0)); - Assert.Equal(3, taken4.ElementAtOrDefault(2)); - Assert.Equal(0, taken4.ElementAtOrDefault(-1)); - Assert.Equal(0, taken4.ElementAtOrDefault(3)); - } - - [Fact] - public void ElementAtOrDefaultNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5, 6 }); - var taken0 = source.Take(3); - Assert.Equal(1, taken0.ElementAtOrDefault(0)); - Assert.Equal(3, taken0.ElementAtOrDefault(2)); - Assert.Equal(0, taken0.ElementAtOrDefault(-1)); - Assert.Equal(0, taken0.ElementAtOrDefault(3)); - - var taken1 = source.Take(0..3); - Assert.Equal(1, taken1.ElementAtOrDefault(0)); - Assert.Equal(3, taken1.ElementAtOrDefault(2)); - Assert.Equal(0, taken1.ElementAtOrDefault(-1)); - Assert.Equal(0, taken1.ElementAtOrDefault(3)); - - var taken2 = source.Take(^6..3); - Assert.Equal(1, taken2.ElementAtOrDefault(0)); - Assert.Equal(3, taken2.ElementAtOrDefault(2)); - Assert.Equal(0, taken2.ElementAtOrDefault(-1)); - Assert.Equal(0, taken2.ElementAtOrDefault(3)); - - var taken3 = source.Take(0..^3); - Assert.Equal(1, taken3.ElementAtOrDefault(0)); - Assert.Equal(3, taken3.ElementAtOrDefault(2)); - Assert.Equal(0, taken3.ElementAtOrDefault(-1)); - Assert.Equal(0, taken3.ElementAtOrDefault(3)); - - var taken4 = source.Take(^6..^3); - Assert.Equal(1, taken4.ElementAtOrDefault(0)); - Assert.Equal(3, taken4.ElementAtOrDefault(2)); - Assert.Equal(0, taken4.ElementAtOrDefault(-1)); - Assert.Equal(0, taken4.ElementAtOrDefault(3)); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5, 6])) + { + var taken0 = source.Take(3); + Assert.Equal(1, taken0.ElementAtOrDefault(0)); + Assert.Equal(3, taken0.ElementAtOrDefault(2)); + Assert.Equal(0, taken0.ElementAtOrDefault(-1)); + Assert.Equal(0, taken0.ElementAtOrDefault(3)); + + var taken1 = source.Take(0..3); + Assert.Equal(1, taken1.ElementAtOrDefault(0)); + Assert.Equal(3, taken1.ElementAtOrDefault(2)); + Assert.Equal(0, taken1.ElementAtOrDefault(-1)); + Assert.Equal(0, taken1.ElementAtOrDefault(3)); + + var taken2 = source.Take(^6..3); + Assert.Equal(1, taken2.ElementAtOrDefault(0)); + Assert.Equal(3, taken2.ElementAtOrDefault(2)); + Assert.Equal(0, taken2.ElementAtOrDefault(-1)); + Assert.Equal(0, taken2.ElementAtOrDefault(3)); + + var taken3 = source.Take(0..^3); + Assert.Equal(1, taken3.ElementAtOrDefault(0)); + Assert.Equal(3, taken3.ElementAtOrDefault(2)); + Assert.Equal(0, taken3.ElementAtOrDefault(-1)); + Assert.Equal(0, taken3.ElementAtOrDefault(3)); + + var taken4 = source.Take(^6..^3); + Assert.Equal(1, taken4.ElementAtOrDefault(0)); + Assert.Equal(3, taken4.ElementAtOrDefault(2)); + Assert.Equal(0, taken4.ElementAtOrDefault(-1)); + Assert.Equal(0, taken4.ElementAtOrDefault(3)); + } } [Fact] public void First() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Take(1).First()); - Assert.Equal(1, source.Take(4).First()); - Assert.Equal(1, source.Take(40).First()); - Assert.Throws(() => source.Take(0).First()); - Assert.Throws(() => source.Skip(5).Take(10).First()); - - Assert.Equal(1, source.Take(0..1).First()); - Assert.Equal(1, source.Take(0..4).First()); - Assert.Equal(1, source.Take(0..40).First()); - Assert.Throws(() => source.Take(0..0).First()); - Assert.Throws(() => source.Skip(5).Take(0..10).First()); - - Assert.Equal(1, source.Take(^5..1).First()); - Assert.Equal(1, source.Take(^5..4).First()); - Assert.Equal(1, source.Take(^5..40).First()); - Assert.Throws(() => source.Take(^5..0).First()); - Assert.Throws(() => source.Skip(5).Take(^5..10).First()); - - Assert.Equal(1, source.Take(0..^4).First()); - Assert.Equal(1, source.Take(0..^1).First()); - Assert.Equal(1, source.Take(0..^0).First()); - Assert.Throws(() => source.Take(0..^5).First()); - Assert.Throws(() => source.Skip(5).Take(0..^5).First()); - - Assert.Equal(1, source.Take(^5..^4).First()); - Assert.Equal(1, source.Take(^5..^1).First()); - Assert.Equal(1, source.Take(^5..^0).First()); - Assert.Throws(() => source.Take(^5..^5).First()); - Assert.Throws(() => source.Skip(5).Take(^10..^0).First()); - } - - [Fact] - public void FirstNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Take(1).First()); - Assert.Equal(1, source.Take(4).First()); - Assert.Equal(1, source.Take(40).First()); - Assert.Throws(() => source.Take(0).First()); - Assert.Throws(() => source.Skip(5).Take(10).First()); - - Assert.Equal(1, source.Take(0..1).First()); - Assert.Equal(1, source.Take(0..4).First()); - Assert.Equal(1, source.Take(0..40).First()); - Assert.Throws(() => source.Take(0..0).First()); - Assert.Throws(() => source.Skip(5).Take(0..10).First()); - - Assert.Equal(1, source.Take(^5..1).First()); - Assert.Equal(1, source.Take(^5..4).First()); - Assert.Equal(1, source.Take(^5..40).First()); - Assert.Throws(() => source.Take(^5..0).First()); - Assert.Throws(() => source.Skip(5).Take(^5..10).First()); - - Assert.Equal(1, source.Take(0..^4).First()); - Assert.Equal(1, source.Take(0..^1).First()); - Assert.Equal(1, source.Take(0..^0).First()); - Assert.Throws(() => source.Take(0..^5).First()); - Assert.Throws(() => source.Skip(5).Take(0..^5).First()); - - Assert.Equal(1, source.Take(^5..^4).First()); - Assert.Equal(1, source.Take(^5..^1).First()); - Assert.Equal(1, source.Take(^5..^0).First()); - Assert.Throws(() => source.Take(^5..^5).First()); - Assert.Throws(() => source.Skip(5).Take(^10..^0).First()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Take(1).First()); + Assert.Equal(1, source.Take(4).First()); + Assert.Equal(1, source.Take(40).First()); + Assert.Throws(() => source.Take(0).First()); + Assert.Throws(() => source.Skip(5).Take(10).First()); + + Assert.Equal(1, source.Take(0..1).First()); + Assert.Equal(1, source.Take(0..4).First()); + Assert.Equal(1, source.Take(0..40).First()); + Assert.Throws(() => source.Take(0..0).First()); + Assert.Throws(() => source.Skip(5).Take(0..10).First()); + + Assert.Equal(1, source.Take(^5..1).First()); + Assert.Equal(1, source.Take(^5..4).First()); + Assert.Equal(1, source.Take(^5..40).First()); + Assert.Throws(() => source.Take(^5..0).First()); + Assert.Throws(() => source.Skip(5).Take(^5..10).First()); + + Assert.Equal(1, source.Take(0..^4).First()); + Assert.Equal(1, source.Take(0..^1).First()); + Assert.Equal(1, source.Take(0..^0).First()); + Assert.Throws(() => source.Take(0..^5).First()); + Assert.Throws(() => source.Skip(5).Take(0..^5).First()); + + Assert.Equal(1, source.Take(^5..^4).First()); + Assert.Equal(1, source.Take(^5..^1).First()); + Assert.Equal(1, source.Take(^5..^0).First()); + Assert.Throws(() => source.Take(^5..^5).First()); + Assert.Throws(() => source.Skip(5).Take(^10..^0).First()); + } } [Fact] public void FirstOrDefault() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Take(1).FirstOrDefault()); - Assert.Equal(1, source.Take(4).FirstOrDefault()); - Assert.Equal(1, source.Take(40).FirstOrDefault()); - Assert.Equal(0, source.Take(0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(10).FirstOrDefault()); - - Assert.Equal(1, source.Take(0..1).FirstOrDefault()); - Assert.Equal(1, source.Take(0..4).FirstOrDefault()); - Assert.Equal(1, source.Take(0..40).FirstOrDefault()); - Assert.Equal(0, source.Take(0..0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(0..10).FirstOrDefault()); - - Assert.Equal(1, source.Take(^5..1).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..4).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..40).FirstOrDefault()); - Assert.Equal(0, source.Take(^5..0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(^10..10).FirstOrDefault()); - - Assert.Equal(1, source.Take(0..^4).FirstOrDefault()); - Assert.Equal(1, source.Take(0..^1).FirstOrDefault()); - Assert.Equal(1, source.Take(0..^0).FirstOrDefault()); - Assert.Equal(0, source.Take(0..^5).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(0..^10).FirstOrDefault()); - - Assert.Equal(1, source.Take(^5..^4).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..^1).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..^0).FirstOrDefault()); - Assert.Equal(0, source.Take(^5..^5).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(^10..^0).FirstOrDefault()); - } - - [Fact] - public void FirstOrDefaultNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Take(1).FirstOrDefault()); - Assert.Equal(1, source.Take(4).FirstOrDefault()); - Assert.Equal(1, source.Take(40).FirstOrDefault()); - Assert.Equal(0, source.Take(0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(10).FirstOrDefault()); - - Assert.Equal(1, source.Take(0..1).FirstOrDefault()); - Assert.Equal(1, source.Take(0..4).FirstOrDefault()); - Assert.Equal(1, source.Take(0..40).FirstOrDefault()); - Assert.Equal(0, source.Take(0..0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(0..10).FirstOrDefault()); - - Assert.Equal(1, source.Take(^5..1).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..4).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..40).FirstOrDefault()); - Assert.Equal(0, source.Take(^5..0).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(^10..10).FirstOrDefault()); - - Assert.Equal(1, source.Take(0..^4).FirstOrDefault()); - Assert.Equal(1, source.Take(0..^1).FirstOrDefault()); - Assert.Equal(1, source.Take(0..^0).FirstOrDefault()); - Assert.Equal(0, source.Take(0..^5).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(0..^10).FirstOrDefault()); - - Assert.Equal(1, source.Take(^5..^4).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..^1).FirstOrDefault()); - Assert.Equal(1, source.Take(^5..^0).FirstOrDefault()); - Assert.Equal(0, source.Take(^5..^5).FirstOrDefault()); - Assert.Equal(0, source.Skip(5).Take(^10..^0).FirstOrDefault()); + foreach (IEnumerable source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Take(1).FirstOrDefault()); + Assert.Equal(1, source.Take(4).FirstOrDefault()); + Assert.Equal(1, source.Take(40).FirstOrDefault()); + Assert.Equal(0, source.Take(0).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).Take(10).FirstOrDefault()); + + Assert.Equal(1, source.Take(0..1).FirstOrDefault()); + Assert.Equal(1, source.Take(0..4).FirstOrDefault()); + Assert.Equal(1, source.Take(0..40).FirstOrDefault()); + Assert.Equal(0, source.Take(0..0).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).Take(0..10).FirstOrDefault()); + + Assert.Equal(1, source.Take(^5..1).FirstOrDefault()); + Assert.Equal(1, source.Take(^5..4).FirstOrDefault()); + Assert.Equal(1, source.Take(^5..40).FirstOrDefault()); + Assert.Equal(0, source.Take(^5..0).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).Take(^10..10).FirstOrDefault()); + + Assert.Equal(1, source.Take(0..^4).FirstOrDefault()); + Assert.Equal(1, source.Take(0..^1).FirstOrDefault()); + Assert.Equal(1, source.Take(0..^0).FirstOrDefault()); + Assert.Equal(0, source.Take(0..^5).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).Take(0..^10).FirstOrDefault()); + + Assert.Equal(1, source.Take(^5..^4).FirstOrDefault()); + Assert.Equal(1, source.Take(^5..^1).FirstOrDefault()); + Assert.Equal(1, source.Take(^5..^0).FirstOrDefault()); + Assert.Equal(0, source.Take(^5..^5).FirstOrDefault()); + Assert.Equal(0, source.Skip(5).Take(^10..^0).FirstOrDefault()); + } } [Fact] public void Last() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Take(1).Last()); - Assert.Equal(5, source.Take(5).Last()); - Assert.Equal(5, source.Take(40).Last()); - Assert.Throws(() => source.Take(0).Last()); - Assert.Throws(() => Array.Empty().Take(40).Last()); - - Assert.Equal(1, source.Take(0..1).Last()); - Assert.Equal(5, source.Take(0..5).Last()); - Assert.Equal(5, source.Take(0..40).Last()); - Assert.Throws(() => source.Take(0..0).Last()); - Assert.Throws(() => Array.Empty().Take(0..40).Last()); - - Assert.Equal(1, source.Take(^5..1).Last()); - Assert.Equal(5, source.Take(^5..5).Last()); - Assert.Equal(5, source.Take(^5..40).Last()); - Assert.Throws(() => source.Take(^5..0).Last()); - Assert.Throws(() => Array.Empty().Take(^5..40).Last()); - - Assert.Equal(1, source.Take(0..^4).Last()); - Assert.Equal(5, source.Take(0..^0).Last()); - Assert.Equal(5, source.Take(3..^0).Last()); - Assert.Throws(() => source.Take(0..^5).Last()); - Assert.Throws(() => Array.Empty().Take(0..^0).Last()); - - Assert.Equal(1, source.Take(^5..^4).Last()); - Assert.Equal(5, source.Take(^5..^0).Last()); - Assert.Equal(5, source.Take(^5..^0).Last()); - Assert.Throws(() => source.Take(^5..^5).Last()); - Assert.Throws(() => Array.Empty().Take(^40..^0).Last()); - } - - [Fact] - public void LastNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Take(1).Last()); - Assert.Equal(5, source.Take(5).Last()); - Assert.Equal(5, source.Take(40).Last()); - Assert.Throws(() => source.Take(0).Last()); - Assert.Throws(() => ForceNotCollection(Array.Empty()).Take(40).Last()); - - Assert.Equal(1, source.Take(0..1).Last()); - Assert.Equal(5, source.Take(0..5).Last()); - Assert.Equal(5, source.Take(0..40).Last()); - Assert.Throws(() => source.Take(0..0).Last()); - Assert.Throws(() => ForceNotCollection(Array.Empty()).Take(0..40).Last()); - - Assert.Equal(1, source.Take(^5..1).Last()); - Assert.Equal(5, source.Take(^5..5).Last()); - Assert.Equal(5, source.Take(^5..40).Last()); - Assert.Throws(() => source.Take(^5..0).Last()); - Assert.Throws(() => ForceNotCollection(Array.Empty()).Take(^5..40).Last()); - - Assert.Equal(1, source.Take(0..^4).Last()); - Assert.Equal(5, source.Take(0..^0).Last()); - Assert.Equal(5, source.Take(3..^0).Last()); - Assert.Throws(() => source.Take(0..^5).Last()); - Assert.Throws(() => ForceNotCollection(Array.Empty()).Take(0..^0).Last()); - - Assert.Equal(1, source.Take(^5..^4).Last()); - Assert.Equal(5, source.Take(^5..^0).Last()); - Assert.Equal(5, source.Take(^5..^0).Last()); - Assert.Throws(() => source.Take(^5..^5).Last()); - Assert.Throws(() => ForceNotCollection(Array.Empty()).Take(^40..^0).Last()); + foreach (var source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Take(1).Last()); + Assert.Equal(2, source.Take(2).Last()); + Assert.Equal(3, source.Take(3).Last()); + Assert.Equal(4, source.Take(4).Last()); + Assert.Equal(5, source.Take(5).Last()); + Assert.Equal(5, source.Take(6).Last()); + Assert.Equal(5, source.Take(40).Last()); + Assert.Throws(() => source.Take(0).Last()); + Assert.Throws(() => Array.Empty().Take(40).Last()); + + Assert.Equal(1, source.Take(0..1).Last()); + Assert.Equal(5, source.Take(0..5).Last()); + Assert.Equal(5, source.Take(0..40).Last()); + Assert.Throws(() => source.Take(0..0).Last()); + Assert.Throws(() => Array.Empty().Take(0..40).Last()); + + Assert.Equal(1, source.Take(^5..1).Last()); + Assert.Equal(5, source.Take(^5..5).Last()); + Assert.Equal(5, source.Take(^5..40).Last()); + Assert.Throws(() => source.Take(^5..0).Last()); + Assert.Throws(() => Array.Empty().Take(^5..40).Last()); + + Assert.Equal(1, source.Take(0..^4).Last()); + Assert.Equal(5, source.Take(0..^0).Last()); + Assert.Equal(5, source.Take(3..^0).Last()); + Assert.Throws(() => source.Take(0..^5).Last()); + Assert.Throws(() => Array.Empty().Take(0..^0).Last()); + + Assert.Equal(1, source.Take(^5..^4).Last()); + Assert.Equal(5, source.Take(^5..^0).Last()); + Assert.Equal(5, source.Take(^5..^0).Last()); + Assert.Throws(() => source.Take(^5..^5).Last()); + Assert.Throws(() => Array.Empty().Take(^40..^0).Last()); + } } [Fact] public void LastOrDefault() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(1, source.Take(1).LastOrDefault()); - Assert.Equal(5, source.Take(5).LastOrDefault()); - Assert.Equal(5, source.Take(40).LastOrDefault()); - Assert.Equal(0, source.Take(0).LastOrDefault()); - Assert.Equal(0, Array.Empty().Take(40).LastOrDefault()); - - Assert.Equal(1, source.Take(0..1).LastOrDefault()); - Assert.Equal(5, source.Take(0..5).LastOrDefault()); - Assert.Equal(5, source.Take(0..40).LastOrDefault()); - Assert.Equal(0, source.Take(0..0).LastOrDefault()); - Assert.Equal(0, Array.Empty().Take(0..40).LastOrDefault()); - - Assert.Equal(1, source.Take(^5..1).LastOrDefault()); - Assert.Equal(5, source.Take(^5..5).LastOrDefault()); - Assert.Equal(5, source.Take(^5..40).LastOrDefault()); - Assert.Equal(0, source.Take(^5..0).LastOrDefault()); - Assert.Equal(0, Array.Empty().Take(^5..40).LastOrDefault()); - - Assert.Equal(1, source.Take(0..^4).LastOrDefault()); - Assert.Equal(5, source.Take(0..^0).LastOrDefault()); - Assert.Equal(5, source.Take(3..^0).LastOrDefault()); - Assert.Equal(0, source.Take(0..^5).LastOrDefault()); - Assert.Equal(0, Array.Empty().Take(0..^0).LastOrDefault()); - - Assert.Equal(1, source.Take(^5..^4).LastOrDefault()); - Assert.Equal(5, source.Take(^5..^0).LastOrDefault()); - Assert.Equal(5, source.Take(^40..^0).LastOrDefault()); - Assert.Equal(0, source.Take(^5..^5).LastOrDefault()); - Assert.Equal(0, Array.Empty().Take(^40..^0).LastOrDefault()); - } - - [Fact] - public void LastOrDefaultNotIList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(1, source.Take(1).LastOrDefault()); - Assert.Equal(5, source.Take(5).LastOrDefault()); - Assert.Equal(5, source.Take(40).LastOrDefault()); - Assert.Equal(0, source.Take(0).LastOrDefault()); - Assert.Equal(0, ForceNotCollection(Array.Empty()).Take(40).LastOrDefault()); - - Assert.Equal(1, source.Take(0..1).LastOrDefault()); - Assert.Equal(5, source.Take(0..5).LastOrDefault()); - Assert.Equal(5, source.Take(0..40).LastOrDefault()); - Assert.Equal(0, source.Take(0..0).LastOrDefault()); - Assert.Equal(0, ForceNotCollection(Array.Empty()).Take(0..40).LastOrDefault()); - - Assert.Equal(1, source.Take(^5..1).LastOrDefault()); - Assert.Equal(5, source.Take(^5..5).LastOrDefault()); - Assert.Equal(5, source.Take(^5..40).LastOrDefault()); - Assert.Equal(0, source.Take(^5..0).LastOrDefault()); - Assert.Equal(0, ForceNotCollection(Array.Empty()).Take(^5..40).LastOrDefault()); - - Assert.Equal(1, source.Take(0..^4).LastOrDefault()); - Assert.Equal(5, source.Take(0..^0).LastOrDefault()); - Assert.Equal(5, source.Take(3..^0).LastOrDefault()); - Assert.Equal(0, source.Take(0..^5).LastOrDefault()); - Assert.Equal(0, ForceNotCollection(Array.Empty()).Take(0..^0).LastOrDefault()); - - Assert.Equal(1, source.Take(^5..^4).LastOrDefault()); - Assert.Equal(5, source.Take(^5..^0).LastOrDefault()); - Assert.Equal(5, source.Take(^40..^0).LastOrDefault()); - Assert.Equal(0, source.Take(^5..^5).LastOrDefault()); - Assert.Equal(0, ForceNotCollection(Array.Empty()).Take(^40..^0).LastOrDefault()); + foreach (var source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(1, source.Take(1).LastOrDefault()); + Assert.Equal(2, source.Take(2).LastOrDefault()); + Assert.Equal(3, source.Take(3).LastOrDefault()); + Assert.Equal(4, source.Take(4).LastOrDefault()); + Assert.Equal(5, source.Take(5).LastOrDefault()); + Assert.Equal(5, source.Take(6).LastOrDefault()); + Assert.Equal(5, source.Take(40).LastOrDefault()); + Assert.Equal(0, source.Take(0).LastOrDefault()); + Assert.Equal(0, Array.Empty().Take(40).LastOrDefault()); + + Assert.Equal(1, source.Take(0..1).LastOrDefault()); + Assert.Equal(5, source.Take(0..5).LastOrDefault()); + Assert.Equal(5, source.Take(0..40).LastOrDefault()); + Assert.Equal(0, source.Take(0..0).LastOrDefault()); + Assert.Equal(0, Array.Empty().Take(0..40).LastOrDefault()); + + Assert.Equal(1, source.Take(^5..1).LastOrDefault()); + Assert.Equal(5, source.Take(^5..5).LastOrDefault()); + Assert.Equal(5, source.Take(^5..40).LastOrDefault()); + Assert.Equal(0, source.Take(^5..0).LastOrDefault()); + Assert.Equal(0, Array.Empty().Take(^5..40).LastOrDefault()); + + Assert.Equal(1, source.Take(0..^4).LastOrDefault()); + Assert.Equal(5, source.Take(0..^0).LastOrDefault()); + Assert.Equal(5, source.Take(3..^0).LastOrDefault()); + Assert.Equal(0, source.Take(0..^5).LastOrDefault()); + Assert.Equal(0, Array.Empty().Take(0..^0).LastOrDefault()); + + Assert.Equal(1, source.Take(^5..^4).LastOrDefault()); + Assert.Equal(5, source.Take(^5..^0).LastOrDefault()); + Assert.Equal(5, source.Take(^40..^0).LastOrDefault()); + Assert.Equal(0, source.Take(^5..^5).LastOrDefault()); + Assert.Equal(0, Array.Empty().Take(^40..^0).LastOrDefault()); + } } [Fact] public void ToArray() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToArray()); - Assert.Equal(1, source.Take(1).ToArray().Single()); - Assert.Empty(source.Take(0).ToArray()); - Assert.Empty(source.Take(-10).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToArray()); - Assert.Equal(1, source.Take(0..1).ToArray().Single()); - Assert.Empty(source.Take(0..0).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToArray()); - Assert.Equal(1, source.Take(^5..1).ToArray().Single()); - Assert.Empty(source.Take(^5..0).ToArray()); - Assert.Empty(source.Take(^15..0).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToArray()); - Assert.Equal(1, source.Take(0..^4).ToArray().Single()); - Assert.Empty(source.Take(0..^5).ToArray()); - Assert.Empty(source.Take(0..^15).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToArray()); - Assert.Equal(1, source.Take(^5..^4).ToArray().Single()); - Assert.Empty(source.Take(^5..^5).ToArray()); - Assert.Empty(source.Take(^15..^5).ToArray()); - } - - [Fact] - public void ToArrayNotList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToArray()); - Assert.Equal(1, source.Take(1).ToArray().Single()); - Assert.Empty(source.Take(0).ToArray()); - Assert.Empty(source.Take(-10).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToArray()); - Assert.Equal(1, source.Take(0..1).ToArray().Single()); - Assert.Empty(source.Take(0..0).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToArray()); - Assert.Equal(1, source.Take(^5..1).ToArray().Single()); - Assert.Empty(source.Take(^5..0).ToArray()); - Assert.Empty(source.Take(^15..0).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToArray()); - Assert.Equal(1, source.Take(0..^4).ToArray().Single()); - Assert.Empty(source.Take(0..^5).ToArray()); - Assert.Empty(source.Take(0..^15).ToArray()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToArray()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToArray()); - Assert.Equal(1, source.Take(^5..^4).ToArray().Single()); - Assert.Empty(source.Take(^5..^5).ToArray()); - Assert.Empty(source.Take(^15..^5).ToArray()); + foreach (var source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToArray()); + Assert.Equal(1, source.Take(1).ToArray().Single()); + Assert.Empty(source.Take(0).ToArray()); + Assert.Empty(source.Take(-10).ToArray()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToArray()); + Assert.Equal(1, source.Take(0..1).ToArray().Single()); + Assert.Empty(source.Take(0..0).ToArray()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToArray()); + Assert.Equal(1, source.Take(^5..1).ToArray().Single()); + Assert.Empty(source.Take(^5..0).ToArray()); + Assert.Empty(source.Take(^15..0).ToArray()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToArray()); + Assert.Equal(1, source.Take(0..^4).ToArray().Single()); + Assert.Empty(source.Take(0..^5).ToArray()); + Assert.Empty(source.Take(0..^15).ToArray()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToArray()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToArray()); + Assert.Equal(1, source.Take(^5..^4).ToArray().Single()); + Assert.Empty(source.Take(^5..^5).ToArray()); + Assert.Empty(source.Take(^15..^5).ToArray()); + } } [Fact] public void ToList() { - var source = new[] { 1, 2, 3, 4, 5 }; - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToList()); - Assert.Equal(1, source.Take(1).ToList().Single()); - Assert.Empty(source.Take(0).ToList()); - Assert.Empty(source.Take(-10).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToList()); - Assert.Equal(1, source.Take(0..1).ToList().Single()); - Assert.Empty(source.Take(0..0).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToList()); - Assert.Equal(1, source.Take(^5..1).ToList().Single()); - Assert.Empty(source.Take(^5..0).ToList()); - Assert.Empty(source.Take(^15..0).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToList()); - Assert.Equal(1, source.Take(0..^4).ToList().Single()); - Assert.Empty(source.Take(0..^5).ToList()); - Assert.Empty(source.Take(0..^15).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToList()); - Assert.Equal(1, source.Take(^5..^4).ToList().Single()); - Assert.Empty(source.Take(^5..^5).ToList()); - Assert.Empty(source.Take(^15..^5).ToList()); - } - - [Fact] - public void ToListNotList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToList()); - Assert.Equal(1, source.Take(1).ToList().Single()); - Assert.Empty(source.Take(0).ToList()); - Assert.Empty(source.Take(-10).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToList()); - Assert.Equal(1, source.Take(0..1).ToList().Single()); - Assert.Empty(source.Take(0..0).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToList()); - Assert.Equal(1, source.Take(^5..1).ToList().Single()); - Assert.Empty(source.Take(^5..0).ToList()); - Assert.Empty(source.Take(^15..0).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToList()); - Assert.Equal(1, source.Take(0..^4).ToList().Single()); - Assert.Empty(source.Take(0..^5).ToList()); - Assert.Empty(source.Take(0..^15).ToList()); - - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToList()); - Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToList()); - Assert.Equal(1, source.Take(^5..^4).ToList().Single()); - Assert.Empty(source.Take(^5..^5).ToList()); - Assert.Empty(source.Take(^15..^5).ToList()); + foreach (var source in CreateSources([1, 2, 3, 4, 5])) + { + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(5).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(6).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(40).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(4).ToList()); + Assert.Equal(1, source.Take(1).ToList().Single()); + Assert.Empty(source.Take(0).ToList()); + Assert.Empty(source.Take(-10).ToList()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..5).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..6).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..40).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..4).ToList()); + Assert.Equal(1, source.Take(0..1).ToList().Single()); + Assert.Empty(source.Take(0..0).ToList()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..5).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..6).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..40).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..4).ToList()); + Assert.Equal(1, source.Take(^5..1).ToList().Single()); + Assert.Empty(source.Take(^5..0).ToList()); + Assert.Empty(source.Take(^15..0).ToList()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(0..^0).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(0..^1).ToList()); + Assert.Equal(1, source.Take(0..^4).ToList().Single()); + Assert.Empty(source.Take(0..^5).ToList()); + Assert.Empty(source.Take(0..^15).ToList()); + + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^5..^0).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^6..^0).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Take(^45..^0).ToList()); + Assert.Equal(new[] { 1, 2, 3, 4 }, source.Take(^5..^1).ToList()); + Assert.Equal(1, source.Take(^5..^4).ToList().Single()); + Assert.Empty(source.Take(^5..^5).ToList()); + Assert.Empty(source.Take(^15..^5).ToList()); + } } [Fact] public void TakeCanOnlyBeOneList() { - var source = new[] { 2, 4, 6, 8, 10 }; - Assert.Equal(new[] { 2 }, source.Take(1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(1)); - Assert.Equal(new[] { 6 }, source.Take(3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(3).Take(1)); - - Assert.Equal(new[] { 2 }, source.Take(0..1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(0..1)); - Assert.Equal(new[] { 6 }, source.Take(0..3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(0..3).Take(0..1)); - - Assert.Equal(new[] { 2 }, source.Take(^5..1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(^4..1)); - Assert.Equal(new[] { 6 }, source.Take(^5..3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(^5..3).Take(^4..1)); - - Assert.Equal(new[] { 2 }, source.Take(0..^4)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(0..^3)); - Assert.Equal(new[] { 6 }, source.Take(0..^2).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(0..^2).Take(0..^2)); - - Assert.Equal(new[] { 2 }, source.Take(^5..^4)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(^4..^3)); - Assert.Equal(new[] { 6 }, source.Take(^5..^2).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(^5..^2).Take(^4..^2)); - } - - [Fact] - public void TakeCanOnlyBeOneNotList() - { - var source = ForceNotCollection(new[] { 2, 4, 6, 8, 10 }); - Assert.Equal(new[] { 2 }, source.Take(1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(1)); - Assert.Equal(new[] { 6 }, source.Take(3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(3).Take(1)); - - Assert.Equal(new[] { 2 }, source.Take(0..1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(0..1)); - Assert.Equal(new[] { 6 }, source.Take(0..3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(0..3).Take(0..1)); - - Assert.Equal(new[] { 2 }, source.Take(^5..1)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(^4..1)); - Assert.Equal(new[] { 6 }, source.Take(^5..3).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(^5..3).Take(^4..1)); - - Assert.Equal(new[] { 2 }, source.Take(0..^4)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(0..^3)); - Assert.Equal(new[] { 6 }, source.Take(0..^2).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(0..^2).Take(0..^2)); - - Assert.Equal(new[] { 2 }, source.Take(^5..^4)); - Assert.Equal(new[] { 4 }, source.Skip(1).Take(^4..^3)); - Assert.Equal(new[] { 6 }, source.Take(^5..^2).Skip(2)); - Assert.Equal(new[] { 2 }, source.Take(^5..^2).Take(^4..^2)); + foreach (var source in CreateSources([2, 4, 6, 8, 10])) + { + Assert.Equal([2], source.Take(1)); + Assert.Equal([4], source.Skip(1).Take(1)); + Assert.Equal([6], source.Take(3).Skip(2)); + Assert.Equal([2], source.Take(3).Take(1)); + + Assert.Equal([2], source.Take(0..1)); + Assert.Equal([4], source.Skip(1).Take(0..1)); + Assert.Equal([6], source.Take(0..3).Skip(2)); + Assert.Equal([2], source.Take(0..3).Take(0..1)); + + Assert.Equal([2], source.Take(^5..1)); + Assert.Equal([4], source.Skip(1).Take(^4..1)); + Assert.Equal([6], source.Take(^5..3).Skip(2)); + Assert.Equal([2], source.Take(^5..3).Take(^4..1)); + + Assert.Equal([2], source.Take(0..^4)); + Assert.Equal([4], source.Skip(1).Take(0..^3)); + Assert.Equal([6], source.Take(0..^2).Skip(2)); + Assert.Equal([2], source.Take(0..^2).Take(0..^2)); + + Assert.Equal([2], source.Take(^5..^4)); + Assert.Equal([4], source.Skip(1).Take(^4..^3)); + Assert.Equal([6], source.Take(^5..^2).Skip(2)); + Assert.Equal([2], source.Take(^5..^2).Take(^4..^2)); + } } [Fact] public void RepeatEnumerating() { - var source = new[] { 1, 2, 3, 4, 5 }; - var taken1 = source.Take(3); - Assert.Equal(taken1, taken1); - - var taken2 = source.Take(0..3); - Assert.Equal(taken2, taken2); - - var taken3 = source.Take(^5..3); - Assert.Equal(taken3, taken3); - - var taken4 = source.Take(0..^2); - Assert.Equal(taken4, taken4); - - var taken5 = source.Take(^5..^2); - Assert.Equal(taken5, taken5); - } - - [Fact] - public void RepeatEnumeratingNotList() - { - var source = ForceNotCollection(new[] { 1, 2, 3, 4, 5 }); - var taken1 = source.Take(3); - Assert.Equal(taken1, taken1); + foreach (var source in CreateSources([1, 2, 3, 4, 5])) + { + var taken1 = source.Take(3); + Assert.Equal(taken1, taken1); - var taken2 = source.Take(0..3); - Assert.Equal(taken2, taken2); + var taken2 = source.Take(0..3); + Assert.Equal(taken2, taken2); - var taken3 = source.Take(^5..3); - Assert.Equal(taken3, taken3); + var taken3 = source.Take(^5..3); + Assert.Equal(taken3, taken3); - var taken4 = source.Take(0..^2); - Assert.Equal(taken4, taken4); + var taken4 = source.Take(0..^2); + Assert.Equal(taken4, taken4); - var taken5 = source.Take(^5..^2); - Assert.Equal(taken5, taken5); + var taken5 = source.Take(^5..^2); + Assert.Equal(taken5, taken5); + } } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized))] diff --git a/src/libraries/System.Linq/tests/WhereTests.cs b/src/libraries/System.Linq/tests/WhereTests.cs index 0cf0ff50cd38a2..a80e8076629ce2 100644 --- a/src/libraries/System.Linq/tests/WhereTests.cs +++ b/src/libraries/System.Linq/tests/WhereTests.cs @@ -1097,44 +1097,40 @@ public void ToCollection(IEnumerable source) [Fact] public void WhereFirstLast() { - Assert.All(IdentityTransforms(), transform => + Assert.All(CreateSources(Enumerable.Range(0, 10)), source => { - IEnumerable data = transform(Enumerable.Range(0, 10)); + Assert.Equal(3, source.Where(i => i == 3).First()); + Assert.Equal(0, source.Where(i => i % 2 == 0).First()); - Assert.Equal(3, data.Where(i => i == 3).First()); - Assert.Equal(0, data.Where(i => i % 2 == 0).First()); + Assert.Equal(3, source.Where(i => i == 3).Last()); + Assert.Equal(8, source.Where(i => i % 2 == 0).Last()); - Assert.Equal(3, data.Where(i => i == 3).Last()); - Assert.Equal(8, data.Where(i => i % 2 == 0).Last()); + Assert.Equal(3, source.Where(i => i == 3).ElementAt(0)); + Assert.Equal(8, source.Where(i => i % 2 == 0).ElementAt(4)); - Assert.Equal(3, data.Where(i => i == 3).ElementAt(0)); - Assert.Equal(8, data.Where(i => i % 2 == 0).ElementAt(4)); - - Assert.Throws(() => data.Where(i => i == 10).First()); - Assert.Throws(() => data.Where(i => i == 10).Last()); - Assert.Throws(() => data.Where(i => i == 10).ElementAt(0)); + Assert.Throws(() => source.Where(i => i == 10).First()); + Assert.Throws(() => source.Where(i => i == 10).Last()); + Assert.Throws(() => source.Where(i => i == 10).ElementAt(0)); }); } [Fact] public void WhereSelectFirstLast() { - Assert.All(IdentityTransforms(), transform => + Assert.All(CreateSources(Enumerable.Range(0, 10)), source => { - IEnumerable data = transform(Enumerable.Range(0, 10)); - - Assert.Equal(6, data.Where(i => i == 3).Select(i => i * 2).First()); - Assert.Equal(0, data.Where(i => i % 2 == 0).Select(i => i * 2).First()); + Assert.Equal(6, source.Where(i => i == 3).Select(i => i * 2).First()); + Assert.Equal(0, source.Where(i => i % 2 == 0).Select(i => i * 2).First()); - Assert.Equal(6, data.Where(i => i == 3).Select(i => i * 2).Last()); - Assert.Equal(16, data.Where(i => i % 2 == 0).Select(i => i * 2).Last()); + Assert.Equal(6, source.Where(i => i == 3).Select(i => i * 2).Last()); + Assert.Equal(16, source.Where(i => i % 2 == 0).Select(i => i * 2).Last()); - Assert.Equal(6, data.Where(i => i == 3).Select(i => i * 2).ElementAt(0)); - Assert.Equal(16, data.Where(i => i % 2 == 0).Select(i => i * 2).ElementAt(4)); + Assert.Equal(6, source.Where(i => i == 3).Select(i => i * 2).ElementAt(0)); + Assert.Equal(16, source.Where(i => i % 2 == 0).Select(i => i * 2).ElementAt(4)); - Assert.Throws(() => data.Where(i => i == 10).Select(i => i * 2).First()); - Assert.Throws(() => data.Where(i => i == 10).Select(i => i * 2).Last()); - Assert.Throws(() => data.Where(i => i == 10).Select(i => i * 2).ElementAt(0)); + Assert.Throws(() => source.Where(i => i == 10).Select(i => i * 2).First()); + Assert.Throws(() => source.Where(i => i == 10).Select(i => i * 2).Last()); + Assert.Throws(() => source.Where(i => i == 10).Select(i => i * 2).ElementAt(0)); }); } @@ -1142,7 +1138,7 @@ public static IEnumerable ToCollectionData() { IEnumerable seq = GenerateRandomSequnce(seed: 0xdeadbeef, count: 10); - foreach (IEnumerable seq2 in IdentityTransforms().Select(t => t(seq))) + foreach (IEnumerable seq2 in CreateSources(seq)) { yield return new object[] { seq2 }; } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs index 7b8cc18c40f3b7..662f7d1fa48e93 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs @@ -9,8 +9,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; - +using Microsoft.DotNet.XUnitExtensions; using Xunit; +using Xunit.Abstractions; namespace System.Net.Security.Tests { @@ -192,6 +193,11 @@ public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials { string targetName = "testTargetName"; + if (PlatformDetection.IsWindowsServer2025) + { + throw new SkipTestException("Empty credentials not supported on Server 2025"); + } + // Ensure there is no confusion between DefaultCredentials / DefaultNetworkCredentials and a // NetworkCredential object with empty user, password and domain. NetworkCredential emptyNetworkCredential = new NetworkCredential("", "", ""); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs index d3e651c160e881..b1bb7d379dcb5b 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs @@ -128,9 +128,8 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z { return Vector128.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector128.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -149,9 +148,9 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z { if (typeof(T) == typeof(double)) return AdvSimd.Arm64.FusedMultiplyAdd(z.AsDouble(), x.AsDouble(), y.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -162,9 +161,8 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z { return Vector256.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector256.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -173,9 +171,9 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); if (typeof(T) == typeof(double)) return Fma.MultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -186,9 +184,8 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z { return Vector512.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector512.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -197,9 +194,9 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z if (typeof(T) == typeof(float)) return Avx512F.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); if (typeof(T) == typeof(double)) return Avx512F.FusedMultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } } } diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs index 94bbfb8fcebe92..2d3ce10a64d0e3 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs @@ -501,7 +501,7 @@ public void SpanDestinationFunctions_ThrowsForTooShortDestination(SpanDestinatio [Theory] [MemberData(nameof(SpanDestinationFunctionsToTest))] - public void SpanDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -639,7 +639,7 @@ public void SpanSpanDestination_ThrowsForTooShortDestination(SpanSpanDestination [Theory] [MemberData(nameof(SpanSpanDestinationFunctionsToTest))] - public void SpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -751,7 +751,7 @@ public void SpanScalarDestination_ThrowsForTooShortDestination(SpanScalarDestina [Theory] [MemberData(nameof(SpanScalarDestinationFunctionsToTest))] - public void SpanScalarDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -851,7 +851,7 @@ public void SpanScalarFloatDestination_ThrowsForTooShortDestination(ScalarSpanDe [Theory] [MemberData(nameof(ScalarSpanFloatDestinationFunctionsToTest))] - public void SpanScalarFloatDestination_ThrowsForOverlapppingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarFloatDestination_ThrowsForOverlappingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -949,7 +949,7 @@ public void SpanIntDestination_ThrowsForTooShortDestination(SpanScalarDestinatio [Theory] [MemberData(nameof(SpanIntDestinationFunctionsToTest))] - public void SpanIntDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanIntDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1091,7 +1091,7 @@ public void SpanSpanSpanDestination_ThrowsForTooShortDestination(SpanSpanSpanDes [Theory] [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] - public void SpanSpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1110,7 +1110,7 @@ public static IEnumerable SpanSpanScalarDestinationFunctionsToTest() { yield return Create(TensorPrimitives.FusedMultiplyAdd, T.FusedMultiplyAdd); yield return Create(TensorPrimitives.Lerp, T.Lerp); - yield return Create(TensorPrimitives.MultiplyAddEstimate, T.FusedMultiplyAdd, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); // TODO: Change T.FusedMultiplyAdd to T.MultiplyAddEstimate when available + yield return Create(TensorPrimitives.MultiplyAddEstimate, T.MultiplyAddEstimate, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); static object[] Create(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; @@ -1206,7 +1206,7 @@ public void SpanSpanScalarDestination_ThrowsForTooShortDestination(SpanSpanScala [Theory] [MemberData(nameof(SpanSpanScalarDestinationFunctionsToTest))] - public void SpanSpanScalarDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanScalarDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1320,7 +1320,7 @@ public void SpanScalarSpanDestination_ThrowsForTooShortDestination(SpanScalarSpa [Theory] [MemberData(nameof(SpanScalarSpanDestinationFunctionsToTest))] - public void SpanScalarSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1474,7 +1474,7 @@ public void SpanDestinationDestinationFunctions_ThrowsForTooShortDestination(Spa [Theory] [MemberData(nameof(SpanDestinationDestinationFunctionsToTest))] - public void SpanDestinationDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanDestinationDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; Assert.Throws(() => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(0, 2), array.AsSpan(4, 2))); @@ -1747,7 +1747,7 @@ public void SpanDestinationFunctions_ThrowsForTooShortDestination(SpanDestinatio [Theory] [MemberData(nameof(SpanDestinationFunctionsToTest))] - public void SpanDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(0, 2))); @@ -1833,7 +1833,7 @@ public void SpanSpanDestination_ThrowsForTooShortDestination(SpanSpanDestination [Theory] [MemberData(nameof(SpanSpanDestinationFunctionsToTest))] - public void SpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(0, 2))); @@ -1915,7 +1915,7 @@ public void SpanScalarDestination_ThrowsForTooShortDestination(SpanScalarDestina [Theory] [MemberData(nameof(SpanScalarDestinationFunctionsToTest))] - public void SpanScalarDestination_ThrowsForOverlapppingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanScalarDestination_ThrowsForOverlappingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; T y = NextRandom(); @@ -1924,6 +1924,149 @@ public void SpanScalarDestination_ThrowsForOverlapppingInputWithOutputs(SpanScal } #endregion + #region Span,Span,Span -> Destination + public static IEnumerable SpanSpanSpanDestinationFunctionsToTest() + { + yield return Create(TensorPrimitives.MultiplyAddEstimate, T.MultiplyAddEstimate, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); + + static object[] Create(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_AllLengths(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengthsIncluding0, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + tensorPrimitivesMethod(x, y, z, destination); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_InPlace(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengthsIncluding0, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + T[] xOrig = x.Span.ToArray(); + + tensorPrimitivesMethod(x, x, x, x); + + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(xOrig[i], xOrig[i], xOrig[i]), x[i], tolerance); + } + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_SpecialValues(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, x); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, y); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, z); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForMismatchedLengths(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => tensorPrimitivesMethod(x, y, z, destination)); + Assert.Throws(() => tensorPrimitivesMethod(x, z, y, destination)); + Assert.Throws(() => tensorPrimitivesMethod(y, x, z, destination)); + Assert.Throws(() => tensorPrimitivesMethod(y, z, x, destination)); + Assert.Throws(() => tensorPrimitivesMethod(z, x, y, destination)); + Assert.Throws(() => tensorPrimitivesMethod(z, y, x, destination)); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForTooShortDestination(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(x, y, z, destination)); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + T[] array = new T[10]; + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(2, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(4, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(6, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(8, 2))); + } + #endregion + #region Shifting/Rotating public static IEnumerable ShiftRotateDestinationFunctionsToTest() { @@ -1989,7 +2132,7 @@ public void ShiftRotateDestination_ThrowsForTooShortDestination(SpanScalarDestin [Theory] [MemberData(nameof(ShiftRotateDestinationFunctionsToTest))] - public void ShiftRotateDestination_ThrowsForOverlapppingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) + public void ShiftRotateDestination_ThrowsForOverlappingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), default, array.AsSpan(0, 2))); @@ -2084,7 +2227,7 @@ public void CopySign_ThrowsForTooShortDestination() } [Fact] - public void CopySign_ThrowsForOverlapppingInputsWithOutputs() + public void CopySign_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; @@ -2347,7 +2490,7 @@ public void ScalarSpanDestination_ThrowsForTooShortDestination(ScalarSpanDestina [Theory] [MemberData(nameof(ScalarSpanDestinationFunctionsToTest))] - public void ScalarSpanDestination_ThrowsForOverlapppingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void ScalarSpanDestination_ThrowsForOverlappingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(default, array.AsSpan(4, 2), array.AsSpan(3, 2))); diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs index 920ed00af7e90f..119f57a1f93759 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs @@ -236,7 +236,7 @@ public void Abs_ThrowsForTooShortDestination() } [Fact] - public void Abs_ThrowsForOverlapppingInputsWithOutputs() + public void Abs_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Abs(array.AsSpan(1, 5), array.AsSpan(0, 5))); @@ -307,7 +307,7 @@ public void Add_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Add_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Add_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Add(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(0, 2))); @@ -366,7 +366,7 @@ public void Add_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Add_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Add_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Add(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -442,7 +442,7 @@ public void AddMultiply_ThreeTensors_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_ThreeTensors_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_ThreeTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); @@ -520,7 +520,7 @@ public void AddMultiply_TensorTensorScalar_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_TensorTensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_TensorTensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), array.AsSpan(4, 2), default(T), array.AsSpan(0, 2))); @@ -596,7 +596,7 @@ public void AddMultiply_TensorScalarTensor_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_TensorScalarTensor_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_TensorScalarTensor_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), default(T), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -704,7 +704,7 @@ public void Cosh_ThrowsForTooShortDestination() } [Fact] - public void Cosh_ThrowsForOverlapppingInputsWithOutputs() + public void Cosh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -876,7 +876,7 @@ public void Divide_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Divide_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Divide_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Divide(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -935,7 +935,7 @@ public void Divide_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Divide_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Divide_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Divide(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -1066,7 +1066,7 @@ public void Exp_ThrowsForTooShortDestination() } [Fact] - public void Exp_ThrowsForOverlapppingInputsWithOutputs() + public void Exp_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1410,7 +1410,7 @@ public void Log_ThrowsForTooShortDestination() } [Fact] - public void Log_ThrowsForOverlapppingInputsWithOutputs() + public void Log_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1495,7 +1495,7 @@ public void Log2_ThrowsForTooShortDestination() } [Fact] - public void Log2_ThrowsForOverlapppingInputsWithOutputs() + public void Log2_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1682,7 +1682,7 @@ public void Max_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Max_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Max_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Max(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -1869,7 +1869,7 @@ public void MaxMagnitude_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void MaxMagnitude_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MaxMagnitude_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MaxMagnitude(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2056,7 +2056,7 @@ public void Min_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Min_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Min_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Min(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2241,7 +2241,7 @@ public void MinMagnitude_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void MinMagnitude_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MinMagnitude_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MinMagnitude(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2315,7 +2315,7 @@ public void Multiply_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Multiply_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Multiply_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Multiply(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2374,7 +2374,7 @@ public void Multiply_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Multiply_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Multiply_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Multiply(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -2450,7 +2450,7 @@ public void MultiplyAdd_ThreeTensors_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_ThreeTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_ThreeTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); @@ -2513,7 +2513,7 @@ public void MultiplyAdd_TensorTensorScalar_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_TensorTensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_TensorTensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), array.AsSpan(4, 2), default(T), array.AsSpan(0, 2))); @@ -2574,7 +2574,7 @@ public void MultiplyAdd_TensorScalarTensor_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_TensorScalarTensor_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_TensorScalarTensor_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), default(T), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2632,7 +2632,7 @@ public void Negate_ThrowsForTooShortDestination() } [Fact] - public void Negate_ThrowsForOverlapppingInputsWithOutputs() + public void Negate_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Negate(array.AsSpan(1, 2), array.AsSpan(0, 2))); @@ -2827,7 +2827,7 @@ public void Sigmoid_ThrowsForEmptyInput() } [Fact] - public void Sigmoid_ThrowsForOverlapppingInputsWithOutputs() + public void Sigmoid_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -2935,7 +2935,7 @@ public void Sinh_ThrowsForTooShortDestination() } [Fact] - public void Sinh_ThrowsForOverlapppingInputsWithOutputs() + public void Sinh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -3019,7 +3019,7 @@ public void SoftMax_ThrowsForEmptyInput() } [Fact] - public void SoftMax_ThrowsForOverlapppingInputsWithOutputs() + public void SoftMax_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -3093,7 +3093,7 @@ public void Subtract_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Subtract_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Subtract_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Subtract(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -3152,7 +3152,7 @@ public void Subtract_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Subtract_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Subtract_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Subtract(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -3317,7 +3317,7 @@ public void Tanh_ThrowsForTooShortDestination() } [Fact] - public void Tanh_ThrowsForOverlapppingInputsWithOutputs() + public void Tanh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs index 5d1b79a3098e05..d59cde103713e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs @@ -27,10 +27,26 @@ private static void GateThreadStart() bool debuggerBreakOnWorkStarvation = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.DebugBreakOnWorkerStarvation", false); + // CPU utilization is updated when the gate thread performs periodic activities (GateActivitiesPeriodMs), so + // that would also affect the actual interval. Set to 0 to disable using CPU utilization and have components + // behave as though CPU utilization is low. The default value of 1 causes CPU utilization to be updated whenever + // the gate thread performs periodic activities. + int cpuUtilizationIntervalMs = + AppContextConfigHelper.GetInt32Config( + "System.Threading.ThreadPool.CpuUtilizationIntervalMs", + "DOTNET_ThreadPool_CpuUtilizationIntervalMs", + defaultValue: 1, + allowNegative: false); + // The first reading is over a time range other than what we are focusing on, so we do not use the read other // than to send it to any runtime-specific implementation that may also use the CPU utilization. CpuUtilizationReader cpuUtilizationReader = default; - _ = cpuUtilizationReader.CurrentUtilization; + int lastCpuUtilizationRefreshTimeMs = 0; + if (cpuUtilizationIntervalMs > 0) + { + lastCpuUtilizationRefreshTimeMs = Environment.TickCount; + _ = cpuUtilizationReader.CurrentUtilization; + } PortableThreadPool threadPoolInstance = ThreadPoolInstance; LowLevelLock threadAdjustmentLock = threadPoolInstance._threadAdjustmentLock; @@ -102,8 +118,17 @@ private static void GateThreadStart() (uint)threadPoolInstance.GetAndResetHighWatermarkCountOfThreadsProcessingUserCallbacks()); } - int cpuUtilization = (int)cpuUtilizationReader.CurrentUtilization; - threadPoolInstance._cpuUtilization = cpuUtilization; + // Determine whether CPU utilization should be updated. CPU utilization is only used by the starvation + // heuristic and hill climbing, and neither of those are active when there is a pending blocking + // adjustment. + if (cpuUtilizationIntervalMs > 0 && + threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && + (uint)(currentTimeMs - lastCpuUtilizationRefreshTimeMs) >= (uint)cpuUtilizationIntervalMs) + { + lastCpuUtilizationRefreshTimeMs = currentTimeMs; + int cpuUtilization = (int)cpuUtilizationReader.CurrentUtilization; + threadPoolInstance._cpuUtilization = cpuUtilization; + } if (!disableStarvationDetection && threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs index 0f7fbc06a9a8eb..29cf2dce305657 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs @@ -15,6 +15,7 @@ internal sealed class ThreadInt64PersistentCounter private static List? t_nodeFinalizationHelpers; private long _overflowCount; + private long _lastReturnedCount; // dummy node serving as a start and end of the ring list private readonly ThreadLocalNode _nodes; @@ -31,6 +32,13 @@ public static void Increment(object threadLocalCountObject) Unsafe.As(threadLocalCountObject).Increment(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decrement(object threadLocalCountObject) + { + Debug.Assert(threadLocalCountObject is ThreadLocalNode); + Unsafe.As(threadLocalCountObject).Decrement(); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Add(object threadLocalCountObject, uint count) { @@ -76,6 +84,17 @@ public long Count count += node.Count; node = node._next; } + + // Ensure that the returned value is monotonically increasing + long lastReturnedCount = _lastReturnedCount; + if (count > lastReturnedCount) + { + _lastReturnedCount = count; + } + else + { + count = lastReturnedCount; + } } finally { @@ -134,6 +153,18 @@ public void Increment() OnAddOverflow(1); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Decrement() + { + if (_count != 0) + { + _count--; + return; + } + + OnAddOverflow(-1); + } + public void Add(uint count) { Debug.Assert(count != 0); @@ -149,7 +180,7 @@ public void Add(uint count) } [MethodImpl(MethodImplOptions.NoInlining)] - private void OnAddOverflow(uint count) + private void OnAddOverflow(long count) { Debug.Assert(count != 0); @@ -161,7 +192,7 @@ private void OnAddOverflow(uint count) counter._lock.Acquire(); try { - counter._overflowCount += (long)_count + count; + counter._overflowCount += _count + count; _count = 0; } finally diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 6fa669046a1f06..7660d427da63fd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1375,6 +1375,9 @@ void IThreadPoolWorkItem.Execute() Debug.Assert(stageBeforeUpdate != QueueProcessingStage.NotScheduled); if (stageBeforeUpdate == QueueProcessingStage.Determining) { + // Discount a work item here to avoid counting this queue processing work item + ThreadInt64PersistentCounter.Decrement( + ThreadPoolWorkQueueThreadLocals.threadLocals!.threadLocalCompletionCountObject!); return; } } @@ -1414,7 +1417,11 @@ void IThreadPoolWorkItem.Execute() currentThread.ResetThreadPoolThread(); } - ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount); + // Discount a work item here to avoid counting this queue processing work item + if (completedCount > 1) + { + ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount - 1); + } } } diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index e380af4d84271a..a178d029091157 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -9,7 +9,6 @@ false true $(BaseIntermediateOutputPath)SuggestedBindingRedirects.targets - $(BeforePack);GeneratePackageTargetsFile Provides classes which read and write resources in a format that supports non-primitive objects. Commonly Used Types: @@ -93,7 +92,8 @@ System.Resources.Extensions.PreserializedResourceWriter + AfterTargets="CoreCompile" + Condition="'$(TargetFramework)' == '$(NetFrameworkMinimum)'">

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy