diff --git a/src/NuGet.Core/NuGet.ProjectModel/DependencyGraphSpec.cs b/src/NuGet.Core/NuGet.ProjectModel/DependencyGraphSpec.cs index 8076a81413e..86e0b689892 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/DependencyGraphSpec.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/DependencyGraphSpec.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using NuGet.Common; using NuGet.Packaging; @@ -253,7 +252,9 @@ public static DependencyGraphSpec Load(string path) case "projects": jsonReader.ReadObject(projectsPropertyName => { +#pragma warning disable CS0612 // Type or member is obsolete PackageSpec packageSpec = JsonPackageSpecReader.GetPackageSpec(jsonReader, name: null, path, EnvironmentVariableWrapper.Instance); +#pragma warning restore CS0612 // Type or member is obsolete dgspec._projects.Add(projectsPropertyName, packageSpec); }); break; diff --git a/src/NuGet.Core/NuGet.ProjectModel/FileFormatException.cs b/src/NuGet.Core/NuGet.ProjectModel/FileFormatException.cs index c2992999a27..5d240d3ce2f 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/FileFormatException.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/FileFormatException.cs @@ -85,6 +85,18 @@ internal static FileFormatException Create(Exception exception, int line, int co return ex.WithFilePath(path).WithLineInfo(line, column); } + internal static FileFormatException Create(Exception exception, string path) + { + var message = string.Format(CultureInfo.CurrentCulture, + Strings.Log_ErrorReadingProjectJson, + path, + exception.Message); + + var ex = new FileFormatException(message, exception); + + return ex.WithFilePath(path); + } + public static FileFormatException Create(string message, JToken value, string path) { var lineInfo = (IJsonLineInfo)value; @@ -101,32 +113,24 @@ internal static FileFormatException Create(string message, int line, int column, return ex.WithFilePath(path).WithLineInfo(line, column); } - internal static FileFormatException Create(Exception exception, string path) + internal static FileFormatException Create(JsonReaderException exception, string path) { - var jex = exception as JsonReaderException; - string message; - if (jex == null) - { - message = string.Format(CultureInfo.CurrentCulture, - Strings.Log_ErrorReadingProjectJson, - path, - exception.Message); - - return new FileFormatException(message, exception).WithFilePath(path); - } - else - { - message = string.Format(CultureInfo.CurrentCulture, - Strings.Log_ErrorReadingProjectJsonWithLocation, - path, jex.LineNumber, - jex.LinePosition, - exception.Message); - - return new FileFormatException(message, exception) - .WithFilePath(path) - .WithLineInfo(jex); - } + message = string.Format(CultureInfo.CurrentCulture, + Strings.Log_ErrorReadingProjectJsonWithLocation, + path, exception.LineNumber, + exception.LinePosition, + exception.Message); + + return new FileFormatException(message, exception) + .WithFilePath(path) + .WithLineInfo(exception); + } + + internal static FileFormatException Create(string message, string path) + { + return new FileFormatException(message) + .WithFilePath(path); } } } diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs new file mode 100644 index 00000000000..fe3f7139ef0 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs @@ -0,0 +1,1825 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Frameworks; +using NuGet.LibraryModel; +using NuGet.Packaging.Core; +using NuGet.RuntimeModel; +using NuGet.Versioning; + +namespace NuGet.ProjectModel +{ + public partial class JsonPackageSpecReader + { + private static readonly byte[] AuthorsPropertyName = Encoding.UTF8.GetBytes("authors"); + private static readonly byte[] BuildOptionsPropertyName = Encoding.UTF8.GetBytes("buildOptions"); + private static readonly byte[] ContentFilesPropertyName = Encoding.UTF8.GetBytes("contentFiles"); + private static readonly byte[] CopyrightPropertyName = Encoding.UTF8.GetBytes("copyright"); + private static readonly byte[] DependenciesPropertyName = Encoding.UTF8.GetBytes("dependencies"); + private static readonly byte[] DescriptionPropertyName = Encoding.UTF8.GetBytes("description"); + private static readonly byte[] LanguagePropertyName = Encoding.UTF8.GetBytes("language"); + private static readonly byte[] PackIncludePropertyName = Encoding.UTF8.GetBytes("packInclude"); + private static readonly byte[] PackOptionsPropertyName = Encoding.UTF8.GetBytes("packOptions"); + private static readonly byte[] ScriptsPropertyName = Encoding.UTF8.GetBytes("scripts"); + private static readonly byte[] FrameworksPropertyName = Encoding.UTF8.GetBytes("frameworks"); + private static readonly byte[] RestorePropertyName = Encoding.UTF8.GetBytes("restore"); + private static readonly byte[] RuntimesPropertyName = Encoding.UTF8.GetBytes("runtimes"); + private static readonly byte[] SupportsPropertyName = Encoding.UTF8.GetBytes("supports"); + private static readonly byte[] TitlePropertyName = Encoding.UTF8.GetBytes("title"); + private static readonly byte[] VersionPropertyName = Encoding.UTF8.GetBytes("version"); + private static readonly byte[] OutputNamePropertyName = Encoding.UTF8.GetBytes("outputName"); + private static readonly byte[] AutoReferencedPropertyName = Encoding.UTF8.GetBytes("autoReferenced"); + private static readonly byte[] ExcludePropertyName = Encoding.UTF8.GetBytes("exclude"); + private static readonly byte[] GeneratePathPropertyPropertyName = Encoding.UTF8.GetBytes("generatePathProperty"); + private static readonly byte[] IncludePropertyName = Encoding.UTF8.GetBytes("include"); + private static readonly byte[] NoWarnPropertyName = Encoding.UTF8.GetBytes("noWarn"); + private static readonly byte[] SuppressParentPropertyName = Encoding.UTF8.GetBytes("suppressParent"); + private static readonly byte[] TargetPropertyName = Encoding.UTF8.GetBytes("target"); + private static readonly byte[] VersionOverridePropertyName = Encoding.UTF8.GetBytes("versionOverride"); + private static readonly byte[] VersionCentrallyManagedPropertyName = Encoding.UTF8.GetBytes("versionCentrallyManaged"); + private static readonly byte[] AliasesPropertyName = Encoding.UTF8.GetBytes("aliases"); + private static readonly byte[] NamePropertyName = Encoding.UTF8.GetBytes("name"); + private static readonly byte[] PrivateAssetsPropertyName = Encoding.UTF8.GetBytes("privateAssets"); + private static readonly byte[] ExcludeFilesPropertyName = Encoding.UTF8.GetBytes("excludeFiles"); + private static readonly byte[] IncludeFilesPropertyName = Encoding.UTF8.GetBytes("includeFiles"); + private static readonly byte[] CentralPackageVersionsManagementEnabledPropertyName = Encoding.UTF8.GetBytes("centralPackageVersionsManagementEnabled"); + private static readonly byte[] CentralPackageVersionOverrideDisabledPropertyName = Encoding.UTF8.GetBytes("centralPackageVersionOverrideDisabled"); + private static readonly byte[] CentralPackageTransitivePinningEnabledPropertyName = Encoding.UTF8.GetBytes("CentralPackageTransitivePinningEnabled"); + private static readonly byte[] ConfigFilePathsPropertyName = Encoding.UTF8.GetBytes("configFilePaths"); + private static readonly byte[] CrossTargetingPropertyName = Encoding.UTF8.GetBytes("crossTargeting"); + private static readonly byte[] FallbackFoldersPropertyName = Encoding.UTF8.GetBytes("fallbackFolders"); + private static readonly byte[] FilesPropertyName = Encoding.UTF8.GetBytes("files"); + private static readonly byte[] LegacyPackagesDirectoryPropertyName = Encoding.UTF8.GetBytes("legacyPackagesDirectory"); + private static readonly byte[] OriginalTargetFrameworksPropertyName = Encoding.UTF8.GetBytes("originalTargetFrameworks"); + private static readonly byte[] OutputPathPropertyName = Encoding.UTF8.GetBytes("outputPath"); + private static readonly byte[] PackagesConfigPathPropertyName = Encoding.UTF8.GetBytes("packagesConfigPath"); + private static readonly byte[] PackagesPathPropertyName = Encoding.UTF8.GetBytes("packagesPath"); + private static readonly byte[] ProjectJsonPathPropertyName = Encoding.UTF8.GetBytes("projectJsonPath"); + private static readonly byte[] ProjectNamePropertyName = Encoding.UTF8.GetBytes("projectName"); + private static readonly byte[] ProjectPathPropertyName = Encoding.UTF8.GetBytes("projectPath"); + private static readonly byte[] ProjectStylePropertyName = Encoding.UTF8.GetBytes("projectStyle"); + private static readonly byte[] ProjectUniqueNamePropertyName = Encoding.UTF8.GetBytes("projectUniqueName"); + private static readonly byte[] RestoreLockPropertiesPropertyName = Encoding.UTF8.GetBytes("restoreLockProperties"); + private static readonly byte[] NuGetLockFilePathPropertyName = Encoding.UTF8.GetBytes("nuGetLockFilePath"); + private static readonly byte[] RestoreLockedModePropertyName = Encoding.UTF8.GetBytes("restoreLockedMode"); + private static readonly byte[] RestorePackagesWithLockFilePropertyName = Encoding.UTF8.GetBytes("restorePackagesWithLockFile"); + private static readonly byte[] RestoreAuditPropertiesPropertyName = Encoding.UTF8.GetBytes("restoreAuditProperties"); + private static readonly byte[] EnableAuditPropertyName = Encoding.UTF8.GetBytes("enableAudit"); + private static readonly byte[] AuditLevelPropertyName = Encoding.UTF8.GetBytes("auditLevel"); + private static readonly byte[] AuditModePropertyName = Encoding.UTF8.GetBytes("auditMode"); + private static readonly byte[] SkipContentFileWritePropertyName = Encoding.UTF8.GetBytes("skipContentFileWrite"); + private static readonly byte[] SourcesPropertyName = Encoding.UTF8.GetBytes("sources"); + private static readonly byte[] ValidateRuntimeAssetsPropertyName = Encoding.UTF8.GetBytes("validateRuntimeAssets"); + private static readonly byte[] WarningPropertiesPropertyName = Encoding.UTF8.GetBytes("warningProperties"); + private static readonly byte[] AllWarningsAsErrorsPropertyName = Encoding.UTF8.GetBytes("allWarningsAsErrors"); + private static readonly byte[] WarnAsErrorPropertyName = Encoding.UTF8.GetBytes("warnAsError"); + private static readonly byte[] WarnNotAsErrorPropertyName = Encoding.UTF8.GetBytes("warnNotAsError"); + private static readonly byte[] ExcludeAssetsPropertyName = Encoding.UTF8.GetBytes("excludeAssets"); + private static readonly byte[] IncludeAssetsPropertyName = Encoding.UTF8.GetBytes("includeAssets"); + private static readonly byte[] TargetAliasPropertyName = Encoding.UTF8.GetBytes("targetAlias"); + private static readonly byte[] AssetTargetFallbackPropertyName = Encoding.UTF8.GetBytes("assetTargetFallback"); + private static readonly byte[] SecondaryFrameworkPropertyName = Encoding.UTF8.GetBytes("secondaryFramework"); + private static readonly byte[] CentralPackageVersionsPropertyName = Encoding.UTF8.GetBytes("centralPackageVersions"); + private static readonly byte[] DownloadDependenciesPropertyName = Encoding.UTF8.GetBytes("downloadDependencies"); + private static readonly byte[] FrameworkAssembliesPropertyName = Encoding.UTF8.GetBytes("frameworkAssemblies"); + private static readonly byte[] FrameworkReferencesPropertyName = Encoding.UTF8.GetBytes("frameworkReferences"); + private static readonly byte[] ImportsPropertyName = Encoding.UTF8.GetBytes("imports"); + private static readonly byte[] RuntimeIdentifierGraphPathPropertyName = Encoding.UTF8.GetBytes("runtimeIdentifierGraphPath"); + private static readonly byte[] WarnPropertyName = Encoding.UTF8.GetBytes("warn"); + private static readonly byte[] IconUrlPropertyName = Encoding.UTF8.GetBytes("iconUrl"); + private static readonly byte[] LicenseUrlPropertyName = Encoding.UTF8.GetBytes("licenseUrl"); + private static readonly byte[] OwnersPropertyName = Encoding.UTF8.GetBytes("owners"); + private static readonly byte[] PackageTypePropertyName = Encoding.UTF8.GetBytes("packageType"); + private static readonly byte[] ProjectUrlPropertyName = Encoding.UTF8.GetBytes("projectUrl"); + private static readonly byte[] ReleaseNotesPropertyName = Encoding.UTF8.GetBytes("releaseNotes"); + private static readonly byte[] RequireLicenseAcceptancePropertyName = Encoding.UTF8.GetBytes("requireLicenseAcceptance"); + private static readonly byte[] SummaryPropertyName = Encoding.UTF8.GetBytes("summary"); + private static readonly byte[] TagsPropertyName = Encoding.UTF8.GetBytes("tags"); + private static readonly byte[] MappingsPropertyName = Encoding.UTF8.GetBytes("mappings"); + private static readonly byte[] HashTagImportPropertyName = Encoding.UTF8.GetBytes("#import"); + private static readonly byte[] ProjectReferencesPropertyName = Encoding.UTF8.GetBytes("projectReferences"); + private static readonly byte[] EmptyStringPropertyName = Encoding.UTF8.GetBytes(string.Empty); + + internal static PackageSpec GetPackageSpecUtf8JsonStreamReader(Stream stream, string name, string packageSpecPath, IEnvironmentVariableReader environmentVariableReader, string snapshotValue = null) + { + var reader = new Utf8JsonStreamReader(stream); + return GetPackageSpec(ref reader, name, packageSpecPath, environmentVariableReader, snapshotValue); + } + + internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, string name, string packageSpecPath, IEnvironmentVariableReader environmentVariableReader, string snapshotValue = null) + { + var packageSpec = new PackageSpec(); + + List compatibilityProfiles = null; + List runtimeDescriptions = null; + var wasPackOptionsSet = false; + var isMappingsNull = false; + string filePath = name == null ? null : Path.GetFullPath(packageSpecPath); + + if (jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(EmptyStringPropertyName)) + { + jsonReader.Skip(); + } +#pragma warning disable CS0612 // Type or member is obsolete + else if (jsonReader.ValueTextEquals(AuthorsPropertyName)) + { + jsonReader.Read(); + if (jsonReader.TokenType == JsonTokenType.StartArray) + { + packageSpec.Authors = jsonReader.ReadStringArrayAsIList()?.ToArray(); + } + packageSpec.Authors ??= []; + } + else if (jsonReader.ValueTextEquals(BuildOptionsPropertyName)) + { + ReadBuildOptions(ref jsonReader, packageSpec); + } + else if (jsonReader.ValueTextEquals(ContentFilesPropertyName)) + { + jsonReader.Read(); + jsonReader.ReadStringArrayAsIList(packageSpec.ContentFiles); + } + else if (jsonReader.ValueTextEquals(CopyrightPropertyName)) + { + packageSpec.Copyright = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(DescriptionPropertyName)) + { + packageSpec.Description = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(LanguagePropertyName)) + { + packageSpec.Language = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(PackIncludePropertyName)) + { + ReadPackInclude(ref jsonReader, packageSpec); + } + else if (jsonReader.ValueTextEquals(PackOptionsPropertyName)) + { + ReadPackOptions(ref jsonReader, packageSpec, ref isMappingsNull); + wasPackOptionsSet = true; + } + else if (jsonReader.ValueTextEquals(ScriptsPropertyName)) + { + ReadScripts(ref jsonReader, packageSpec); + } +#pragma warning restore CS0612 // Type or member is + else if (jsonReader.ValueTextEquals(DependenciesPropertyName)) + { + ReadDependencies( + ref jsonReader, + packageSpec.Dependencies, + filePath, + isGacOrFrameworkReference: false); + } + else if (jsonReader.ValueTextEquals(FrameworksPropertyName)) + { + ReadFrameworks(ref jsonReader, packageSpec); + } + else if (jsonReader.ValueTextEquals(RestorePropertyName)) + { + ReadMSBuildMetadata(ref jsonReader, packageSpec, environmentVariableReader); + } + else if (jsonReader.ValueTextEquals(RuntimesPropertyName)) + { + runtimeDescriptions = ReadRuntimes(ref jsonReader); + } + else if (jsonReader.ValueTextEquals(SupportsPropertyName)) + { + compatibilityProfiles = ReadSupports(ref jsonReader); + } + else if (jsonReader.ValueTextEquals(TitlePropertyName)) + { + packageSpec.Title = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(VersionPropertyName)) + { + string version = jsonReader.ReadNextTokenAsString(); + if (version != null) + { + try + { +#pragma warning disable CS0612 // Type or member is obsolete + packageSpec.HasVersionSnapshot = PackageSpecUtility.IsSnapshotVersion(version); +#pragma warning restore CS0612 // Type or member is obsolete + packageSpec.Version = PackageSpecUtility.SpecifySnapshot(version, snapshotValue); + } + catch (Exception ex) + { + throw FileFormatException.Create(ex, version, packageSpec.FilePath); + } + } + } + else + { + jsonReader.Skip(); + } + } + } + packageSpec.Name = name; + packageSpec.FilePath = name == null ? null : Path.GetFullPath(packageSpecPath); + +#pragma warning disable CS0612 // Type or member is obsolete + if (!wasPackOptionsSet) + { + packageSpec.Owners = []; + packageSpec.PackOptions = new PackOptions() + { + PackageType = Array.Empty() + }; + packageSpec.Tags = []; + } + + if (isMappingsNull) + { + packageSpec.PackOptions.Mappings = null; + } +#pragma warning restore CS0612 // Type or member is obsolete + + packageSpec.RuntimeGraph = new RuntimeGraph( + runtimeDescriptions ?? Enumerable.Empty(), + compatibilityProfiles ?? Enumerable.Empty()); + + packageSpec.Name ??= packageSpec.RestoreMetadata?.ProjectName; + + // Use the project.json path if one is set, otherwise use the project path + packageSpec.FilePath ??= packageSpec.RestoreMetadata?.ProjectJsonPath + ?? packageSpec.RestoreMetadata?.ProjectPath; + + return packageSpec; + } + + internal static void ReadCentralTransitiveDependencyGroup( + ref Utf8JsonStreamReader jsonReader, + out IList results, + string packageSpecPath) + { + results = null; + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var libraryName = jsonReader.GetString(); + if (string.IsNullOrEmpty(libraryName)) + { + throw FileFormatException.Create( + "Unable to resolve dependency ''.", + packageSpecPath); + } + + if (jsonReader.Read()) + { + var libraryDependency = ReadLibraryDependency(ref jsonReader, packageSpecPath, libraryName); + results ??= []; + results.Add(libraryDependency); + } + } + } + results ??= Array.Empty(); + } + + private static LibraryDependency ReadLibraryDependency(ref Utf8JsonStreamReader jsonReader, string packageSpecPath, string libraryName) + { + var dependencyIncludeFlagsValue = LibraryIncludeFlags.All; + var dependencyExcludeFlagsValue = LibraryIncludeFlags.None; + var suppressParentFlagsValue = LibraryIncludeFlagUtils.DefaultSuppressParent; + string dependencyVersionValue = null; + + if (jsonReader.TokenType == JsonTokenType.String) + { + dependencyVersionValue = jsonReader.GetString(); + } + else if (jsonReader.TokenType == JsonTokenType.StartObject) + { + ReadCentralTransitiveDependencyGroupProperties( + ref jsonReader, + ref dependencyIncludeFlagsValue, + ref dependencyExcludeFlagsValue, + ref suppressParentFlagsValue, + ref dependencyVersionValue); + } + + VersionRange dependencyVersionRange = null; + + if (!string.IsNullOrEmpty(dependencyVersionValue)) + { + try + { + dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + } + catch (Exception ex) + { + throw FileFormatException.Create( + ex, + packageSpecPath); + } + } + + if (dependencyVersionRange == null) + { + throw FileFormatException.Create( + new ArgumentException(Strings.MissingVersionOnDependency), + packageSpecPath); + } + + // the dependency flags are: Include flags - Exclude flags + var includeFlags = dependencyIncludeFlagsValue & ~dependencyExcludeFlagsValue; + var libraryDependency = new LibraryDependency() + { + LibraryRange = new LibraryRange() + { + Name = libraryName, + TypeConstraint = LibraryDependencyTarget.Package, + VersionRange = dependencyVersionRange + }, + + IncludeType = includeFlags, + SuppressParent = suppressParentFlagsValue, + VersionCentrallyManaged = true, + ReferenceType = LibraryDependencyReferenceType.Transitive + }; + + return libraryDependency; + } + + private static void ReadCentralTransitiveDependencyGroupProperties( + ref Utf8JsonStreamReader jsonReader, + ref LibraryIncludeFlags dependencyIncludeFlagsValue, + ref LibraryIncludeFlags dependencyExcludeFlagsValue, + ref LibraryIncludeFlags suppressParentFlagsValue, + ref string dependencyVersionValue) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(ExcludePropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + dependencyExcludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(IncludePropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + dependencyIncludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(SuppressParentPropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + suppressParentFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(VersionPropertyName)) + { + if (jsonReader.Read()) + { + dependencyVersionValue = jsonReader.GetString(); + } + } + else + { + jsonReader.Skip(); + } + } + } + + private static void ReadDependencies( + ref Utf8JsonStreamReader jsonReader, + IList results, + string packageSpecPath, + bool isGacOrFrameworkReference) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + if (string.IsNullOrEmpty(propertyName)) + { + throw FileFormatException.Create("Unable to resolve dependency ''.", packageSpecPath); + } + + // Support + // "dependencies" : { + // "Name" : "1.0" + // } + + if (jsonReader.Read()) + { + var dependencyIncludeFlagsValue = LibraryIncludeFlags.All; + var dependencyExcludeFlagsValue = LibraryIncludeFlags.None; + var suppressParentFlagsValue = LibraryIncludeFlagUtils.DefaultSuppressParent; + List noWarn = null; + + // This method handles both the dependencies and framework assembly sections. + // Framework references should be limited to references. + // Dependencies should allow everything but framework references. + LibraryDependencyTarget targetFlagsValue = isGacOrFrameworkReference + ? LibraryDependencyTarget.Reference + : LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference; + + var autoReferenced = false; + var generatePathProperty = false; + var versionCentrallyManaged = false; + string aliases = null; + string dependencyVersionValue = null; + VersionRange versionOverride = null; + + if (jsonReader.TokenType == JsonTokenType.String) + { + dependencyVersionValue = jsonReader.GetString(); + } + else if (jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(AutoReferencedPropertyName)) + { + autoReferenced = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(ExcludePropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + dependencyExcludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(GeneratePathPropertyPropertyName)) + { + generatePathProperty = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(IncludePropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + dependencyIncludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(NoWarnPropertyName)) + { + noWarn = ReadNuGetLogCodesList(ref jsonReader); + } + else if (jsonReader.ValueTextEquals(SuppressParentPropertyName)) + { + var values = jsonReader.ReadDelimitedString(); + suppressParentFlagsValue = LibraryIncludeFlagUtils.GetFlags(values); + } + else if (jsonReader.ValueTextEquals(TargetPropertyName)) + { + targetFlagsValue = ReadTarget(ref jsonReader, packageSpecPath, targetFlagsValue); + } + else if (jsonReader.ValueTextEquals(VersionPropertyName)) + { + if (jsonReader.Read()) + { + dependencyVersionValue = jsonReader.GetString(); + } + } + else if (jsonReader.ValueTextEquals(VersionOverridePropertyName)) + { + if (jsonReader.Read()) + { + var versionPropValue = jsonReader.GetString(); + try + { + versionOverride = VersionRange.Parse(versionPropValue); + } + catch (Exception ex) + { + throw FileFormatException.Create(ex, packageSpecPath); + } + } + } + else if (jsonReader.ValueTextEquals(VersionCentrallyManagedPropertyName)) + { + versionCentrallyManaged = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(AliasesPropertyName)) + { + aliases = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + } + + VersionRange dependencyVersionRange = null; + + if (!string.IsNullOrEmpty(dependencyVersionValue)) + { + try + { + dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + } + catch (Exception ex) + { + throw FileFormatException.Create( + ex, + packageSpecPath); + } + } + + // Projects and References may have empty version ranges, Packages may not + if (dependencyVersionRange == null) + { + if ((targetFlagsValue & LibraryDependencyTarget.Package) == LibraryDependencyTarget.Package) + { + throw FileFormatException.Create( + new ArgumentException(Strings.MissingVersionOnDependency), + packageSpecPath); + } + else + { + // Projects and references with no version property allow all versions + dependencyVersionRange = VersionRange.All; + } + } + + // the dependency flags are: Include flags - Exclude flags + var includeFlags = dependencyIncludeFlagsValue & ~dependencyExcludeFlagsValue; + var libraryDependency = new LibraryDependency() + { + LibraryRange = new LibraryRange() + { + Name = propertyName, + TypeConstraint = targetFlagsValue, + VersionRange = dependencyVersionRange + }, + IncludeType = includeFlags, + SuppressParent = suppressParentFlagsValue, + AutoReferenced = autoReferenced, + GeneratePathProperty = generatePathProperty, + VersionCentrallyManaged = versionCentrallyManaged, + Aliases = aliases, + // The ReferenceType is not persisted to the assets file + // Default to LibraryDependencyReferenceType.Direct on Read + ReferenceType = LibraryDependencyReferenceType.Direct, + VersionOverride = versionOverride + }; + + if (noWarn != null) + { + libraryDependency.NoWarn = noWarn; + } + + results.Add(libraryDependency); + } + } + } + } + + private static PackageType CreatePackageType(ref Utf8JsonStreamReader jsonReader) + { + var name = jsonReader.GetString(); + + return new PackageType(name, Packaging.Core.PackageType.EmptyVersion); + } + + [Obsolete] + private static void ReadBuildOptions(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) + { + packageSpec.BuildOptions = new BuildOptions(); + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(OutputNamePropertyName)) + { + packageSpec.BuildOptions.OutputName = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + } + } + + private static void ReadCentralPackageVersions( + ref Utf8JsonStreamReader jsonReader, + IDictionary centralPackageVersions, + string filePath) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + + if (string.IsNullOrEmpty(propertyName)) + { + throw FileFormatException.Create("Unable to resolve central version ''.", filePath); + } + + string version = jsonReader.ReadNextTokenAsString(); + + if (string.IsNullOrEmpty(version)) + { + throw FileFormatException.Create("The version cannot be null or empty.", filePath); + } + + centralPackageVersions[propertyName] = new CentralPackageVersion(propertyName, VersionRange.Parse(version)); + } + } + } + + private static CompatibilityProfile ReadCompatibilityProfile(ref Utf8JsonStreamReader jsonReader, string profileName) + { + List sets = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + sets ??= []; + + IReadOnlyList values = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList() ?? Array.Empty(); + + IEnumerable profiles = ReadCompatibilitySets(values, propertyName); + + sets.AddRange(profiles); + } + } + return new CompatibilityProfile(profileName, sets ?? Enumerable.Empty()); + } + + private static IEnumerable ReadCompatibilitySets(IReadOnlyList values, string compatibilitySetName) + { + NuGetFramework framework = NuGetFramework.Parse(compatibilitySetName); + + foreach (string value in values) + { + yield return new FrameworkRuntimePair(framework, value); + } + } + + private static void ReadDownloadDependencies( + ref Utf8JsonStreamReader jsonReader, + IList downloadDependencies, + string packageSpecPath) + { + var seenIds = new HashSet(); + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartArray) + { + do + { + string name = null; + string versionValue = null; + var isNameDefined = false; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(NamePropertyName)) + { + isNameDefined = true; + name = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(VersionPropertyName)) + { + versionValue = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + } + + if (jsonReader.TokenType == JsonTokenType.EndArray) + { + break; + } + + if (!isNameDefined) + { + throw FileFormatException.Create( + "Unable to resolve downloadDependency ''.", + packageSpecPath); + } + + if (!seenIds.Add(name)) + { + // package ID already seen, only use first definition. + continue; + } + + if (string.IsNullOrEmpty(versionValue)) + { + throw FileFormatException.Create( + "The version cannot be null or empty", + packageSpecPath); + } + + var versions = new LazyStringSplit(versionValue, VersionSeparator); + + foreach (string singleVersionValue in versions) + { + if (string.IsNullOrEmpty(singleVersionValue)) + { + continue; + } + + try + { + VersionRange version = VersionRange.Parse(singleVersionValue); + + downloadDependencies.Add(new DownloadDependency(name, version)); + } + catch (Exception ex) + { + throw FileFormatException.Create( + ex, + packageSpecPath); + } + } + } while (jsonReader.TokenType == JsonTokenType.EndObject); + } + } + + private static void ReadFrameworkReferences( + ref Utf8JsonStreamReader jsonReader, + ISet frameworkReferences, + string packageSpecPath) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var frameworkName = jsonReader.GetString(); + if (string.IsNullOrEmpty(frameworkName)) + { + throw FileFormatException.Create( + "Unable to resolve frameworkReference.", + packageSpecPath); + } + + var privateAssets = FrameworkDependencyFlagsUtils.Default; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(PrivateAssetsPropertyName)) + { + IEnumerable strings = jsonReader.ReadDelimitedString(); + + privateAssets = FrameworkDependencyFlagsUtils.GetFlags(strings); + } + else + { + jsonReader.Skip(); + } + } + } + + frameworkReferences.Add(new FrameworkDependency(frameworkName, privateAssets)); + } + } + } + + private static void ReadFrameworks(ref Utf8JsonStreamReader reader, PackageSpec packageSpec) + { + if (reader.Read() && reader.TokenType == JsonTokenType.StartObject) + { + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + try + { + ReadTargetFrameworks(packageSpec, ref reader); + } + catch (Exception ex) + { + throw FileFormatException.Create(ex, packageSpec.FilePath); + } + } + } + } + + private static void ReadImports(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader, TargetFrameworkInformation targetFrameworkInformation) + { + IReadOnlyList imports = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + if (imports != null && imports.Count > 0) + { + foreach (string import in imports.Where(element => !string.IsNullOrEmpty(element))) + { + NuGetFramework framework = NuGetFramework.Parse(import); + + if (!framework.IsSpecificFramework) + { + throw FileFormatException.Create( + string.Format( + CultureInfo.CurrentCulture, + Strings.Log_InvalidImportFramework, + import, + PackageSpec.PackageSpecFileName), + packageSpec.FilePath); + } + + targetFrameworkInformation.Imports.Add(framework); + } + } + } + + private static void ReadMappings(ref Utf8JsonStreamReader jsonReader, string mappingKey, IDictionary mappings) + { + if (jsonReader.Read()) + { + switch (jsonReader.TokenType) + { + case JsonTokenType.String: + { + var files = new IncludeExcludeFiles() + { + Include = new[] { (string)jsonReader.GetString() } + }; + + mappings.Add(mappingKey, files); + } + break; + case JsonTokenType.StartArray: + { + IReadOnlyList include = jsonReader.ReadStringArrayAsReadOnlyListFromArrayStart(); + + var files = new IncludeExcludeFiles() + { + Include = include + }; + + mappings.Add(mappingKey, files); + } + break; + case JsonTokenType.StartObject: + { + IReadOnlyList excludeFiles = null; + IReadOnlyList exclude = null; + IReadOnlyList includeFiles = null; + IReadOnlyList include = null; + + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(ExcludeFilesPropertyName)) + { + excludeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(ExcludePropertyName)) + { + exclude = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(IncludeFilesPropertyName)) + { + includeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(IncludePropertyName)) + { + include = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else + { + jsonReader.Skip(); + } + } + + if (include != null || includeFiles != null || exclude != null || excludeFiles != null) + { + var files = new IncludeExcludeFiles() + { + ExcludeFiles = excludeFiles, + Exclude = exclude, + IncludeFiles = includeFiles, + Include = include + }; + + mappings.Add(mappingKey, files); + } + } + break; + } + } + } + + private static void ReadMSBuildMetadata(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec, IEnvironmentVariableReader environmentVariableReader) + { + var centralPackageVersionsManagementEnabled = false; + var centralPackageVersionOverrideDisabled = false; + var CentralPackageTransitivePinningEnabled = false; + List configFilePaths = null; + var crossTargeting = false; + List fallbackFolders = null; + List files = null; + var legacyPackagesDirectory = false; + List originalTargetFrameworks = null; + string outputPath = null; + string packagesConfigPath = null; + string packagesPath = null; + string projectJsonPath = null; + string projectName = null; + string projectPath = null; + ProjectStyle? projectStyle = null; + string projectUniqueName = null; + RestoreLockProperties restoreLockProperties = null; + var skipContentFileWrite = false; + List sources = null; + IList targetFrameworks = null; + var validateRuntimeAssets = false; + WarningProperties warningProperties = null; + RestoreAuditProperties auditProperties = null; + bool useMacros = MSBuildStringUtility.IsTrue(environmentVariableReader.GetEnvironmentVariable(MacroStringsUtility.NUGET_ENABLE_EXPERIMENTAL_MACROS)); + var userSettingsDirectory = NuGetEnvironment.GetFolderPath(NuGetFolderPath.UserSettingsDirectory); + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(CentralPackageVersionsManagementEnabledPropertyName)) + { + centralPackageVersionsManagementEnabled = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(CentralPackageVersionOverrideDisabledPropertyName)) + { + centralPackageVersionOverrideDisabled = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(CentralPackageTransitivePinningEnabledPropertyName)) + { + CentralPackageTransitivePinningEnabled = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(ConfigFilePathsPropertyName)) + { + jsonReader.Read(); + configFilePaths = jsonReader.ReadStringArrayAsIList() as List; + ExtractMacros(configFilePaths, userSettingsDirectory, useMacros); + } + else if (jsonReader.ValueTextEquals(CrossTargetingPropertyName)) + { + crossTargeting = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(FallbackFoldersPropertyName)) + { + jsonReader.Read(); + fallbackFolders = jsonReader.ReadStringArrayAsIList() as List; + ExtractMacros(fallbackFolders, userSettingsDirectory, useMacros); + } + else if (jsonReader.ValueTextEquals(FilesPropertyName)) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var filePropertyName = jsonReader.GetString(); + files ??= []; + + files.Add(new ProjectRestoreMetadataFile(filePropertyName, jsonReader.ReadNextTokenAsString())); + } + } + } + else if (jsonReader.ValueTextEquals(FrameworksPropertyName)) + { + targetFrameworks = ReadTargetFrameworks(ref jsonReader); + } + else if (jsonReader.ValueTextEquals(LegacyPackagesDirectoryPropertyName)) + { + legacyPackagesDirectory = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(OriginalTargetFrameworksPropertyName)) + { + jsonReader.Read(); + originalTargetFrameworks = jsonReader.ReadStringArrayAsIList() as List; + } + else if (jsonReader.ValueTextEquals(OutputPathPropertyName)) + { + outputPath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(PackagesConfigPathPropertyName)) + { + packagesConfigPath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(PackagesPathPropertyName)) + { + packagesPath = ExtractMacro(jsonReader.ReadNextTokenAsString(), userSettingsDirectory, useMacros); + } + else if (jsonReader.ValueTextEquals(ProjectJsonPathPropertyName)) + { + projectJsonPath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(ProjectNamePropertyName)) + { + projectName = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(ProjectPathPropertyName)) + { + projectPath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(ProjectStylePropertyName)) + { + string projectStyleString = jsonReader.ReadNextTokenAsString(); + + if (!string.IsNullOrEmpty(projectStyleString) + && Enum.TryParse(projectStyleString, ignoreCase: true, result: out ProjectStyle projectStyleValue)) + { + projectStyle = projectStyleValue; + } + } + else if (jsonReader.ValueTextEquals(ProjectUniqueNamePropertyName)) + { + projectUniqueName = ExtractMacro(jsonReader.ReadNextTokenAsString(), userSettingsDirectory, useMacros); + } + else if (jsonReader.ValueTextEquals(RestoreLockPropertiesPropertyName)) + { + string nuGetLockFilePath = null; + var restoreLockedMode = false; + string restorePackagesWithLockFile = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(NuGetLockFilePathPropertyName)) + { + nuGetLockFilePath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(RestoreLockedModePropertyName)) + { + restoreLockedMode = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(RestorePackagesWithLockFilePropertyName)) + { + restorePackagesWithLockFile = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + } + restoreLockProperties = new RestoreLockProperties(restorePackagesWithLockFile, nuGetLockFilePath, restoreLockedMode); + } + else if (jsonReader.ValueTextEquals(RestoreAuditPropertiesPropertyName)) + { + string enableAudit = null, auditLevel = null, auditMode = null; + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(EnableAuditPropertyName)) + { + enableAudit = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(AuditLevelPropertyName)) + { + auditLevel = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(AuditModePropertyName)) + { + auditMode = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + } + auditProperties = new RestoreAuditProperties() + { + EnableAudit = enableAudit, + AuditLevel = auditLevel, + AuditMode = auditMode, + }; + } + else if (jsonReader.ValueTextEquals(SkipContentFileWritePropertyName)) + { + skipContentFileWrite = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(SourcesPropertyName)) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var sourcePropertyName = jsonReader.GetString(); + sources ??= []; + + sources.Add(new PackageSource(sourcePropertyName)); + jsonReader.Skip(); + } + } + } + else if (jsonReader.ValueTextEquals(ValidateRuntimeAssetsPropertyName)) + { + validateRuntimeAssets = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(WarningPropertiesPropertyName)) + { + var allWarningsAsErrors = false; + var noWarn = new HashSet(); + var warnAsError = new HashSet(); + var warningsNotAsErrors = new HashSet(); + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(AllWarningsAsErrorsPropertyName)) + { + allWarningsAsErrors = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(NoWarnPropertyName)) + { + ReadNuGetLogCodes(ref jsonReader, noWarn); + } + else if (jsonReader.ValueTextEquals(WarnAsErrorPropertyName)) + { + ReadNuGetLogCodes(ref jsonReader, warnAsError); + } + else if (jsonReader.ValueTextEquals(WarnNotAsErrorPropertyName)) + { + ReadNuGetLogCodes(ref jsonReader, warningsNotAsErrors); + } + else + { + jsonReader.Skip(); + } + } + } + + warningProperties = new WarningProperties(warnAsError, noWarn, allWarningsAsErrors, warningsNotAsErrors); + } + else + { + jsonReader.Skip(); + } + } + } + + ProjectRestoreMetadata msbuildMetadata; + if (projectStyle == ProjectStyle.PackagesConfig) + { + msbuildMetadata = new PackagesConfigProjectRestoreMetadata() + { + PackagesConfigPath = packagesConfigPath + }; + } + else + { + msbuildMetadata = new ProjectRestoreMetadata(); + } + + msbuildMetadata.CentralPackageVersionsEnabled = centralPackageVersionsManagementEnabled; + msbuildMetadata.CentralPackageVersionOverrideDisabled = centralPackageVersionOverrideDisabled; + msbuildMetadata.CentralPackageTransitivePinningEnabled = CentralPackageTransitivePinningEnabled; + msbuildMetadata.RestoreAuditProperties = auditProperties; + + if (configFilePaths != null) + { + msbuildMetadata.ConfigFilePaths = configFilePaths; + } + + msbuildMetadata.CrossTargeting = crossTargeting; + + if (fallbackFolders != null) + { + msbuildMetadata.FallbackFolders = fallbackFolders; + } + + if (files != null) + { + msbuildMetadata.Files = files; + } + + msbuildMetadata.LegacyPackagesDirectory = legacyPackagesDirectory; + + if (originalTargetFrameworks != null) + { + msbuildMetadata.OriginalTargetFrameworks = originalTargetFrameworks; + } + + msbuildMetadata.OutputPath = outputPath; + msbuildMetadata.PackagesPath = packagesPath; + msbuildMetadata.ProjectJsonPath = projectJsonPath; + msbuildMetadata.ProjectName = projectName; + msbuildMetadata.ProjectPath = projectPath; + + if (projectStyle.HasValue) + { + msbuildMetadata.ProjectStyle = projectStyle.Value; + } + + msbuildMetadata.ProjectUniqueName = projectUniqueName; + + if (restoreLockProperties != null) + { + msbuildMetadata.RestoreLockProperties = restoreLockProperties; + } + + msbuildMetadata.SkipContentFileWrite = skipContentFileWrite; + + if (sources != null) + { + msbuildMetadata.Sources = sources; + } + + if (targetFrameworks != null) + { + msbuildMetadata.TargetFrameworks = targetFrameworks; + } + + msbuildMetadata.ValidateRuntimeAssets = validateRuntimeAssets; + + if (warningProperties != null) + { + msbuildMetadata.ProjectWideWarningProperties = warningProperties; + } + + packageSpec.RestoreMetadata = msbuildMetadata; + } + + private static void ReadNuGetLogCodes(ref Utf8JsonStreamReader jsonReader, HashSet hashCodes) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartArray) + { + while (jsonReader.Read() && jsonReader.TokenType != JsonTokenType.EndArray) + { + if (jsonReader.TokenType == JsonTokenType.String && Enum.TryParse(jsonReader.GetString(), out NuGetLogCode code)) + { + hashCodes.Add(code); + } + } + } + } + + private static List ReadNuGetLogCodesList(ref Utf8JsonStreamReader jsonReader) + { + List items = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartArray) + { + while (jsonReader.Read() && jsonReader.TokenType != JsonTokenType.EndArray) + { + if (jsonReader.TokenType == JsonTokenType.String && Enum.TryParse(jsonReader.GetString(), out NuGetLogCode code)) + { + items ??= []; + + items.Add(code); + } + } + } + return items; + } + + private static void ReadPackageTypes(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader) + { + IReadOnlyList packageTypes = null; + try + { + if (jsonReader.Read()) + { + PackageType packageType; + switch (jsonReader.TokenType) + { + case JsonTokenType.String: + packageType = CreatePackageType(ref jsonReader); + packageTypes = new[] { packageType }; + break; + case JsonTokenType.StartArray: + List types = null; + + while (jsonReader.Read() && jsonReader.TokenType != JsonTokenType.EndArray) + { + if (jsonReader.TokenType != JsonTokenType.String) + { + throw FileFormatException.Create( + string.Format( + CultureInfo.CurrentCulture, + Strings.InvalidPackageType, + PackageSpec.PackageSpecFileName), + packageSpec.FilePath); + } + + packageType = CreatePackageType(ref jsonReader); + types ??= []; + types.Add(packageType); + } + + packageTypes = types; + break; + case JsonTokenType.Null: + break; + default: + throw new InvalidCastException(); + } + +#pragma warning disable CS0612 // Type or member is obsolete + if (packageTypes != null) + { + packageSpec.PackOptions.PackageType = packageTypes; + } +#pragma warning restore CS0612 // Type or member is obsolete + } + } + catch (Exception) + { + throw FileFormatException.Create( + string.Format( + CultureInfo.CurrentCulture, + Strings.InvalidPackageType, + PackageSpec.PackageSpecFileName), + packageSpec.FilePath); + } + } + + [Obsolete] + private static void ReadPackInclude(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + string propertyName = jsonReader.GetString(); + string propertyValue = jsonReader.ReadNextTokenAsString(); + + packageSpec.PackInclude.Add(new KeyValuePair(propertyName, propertyValue)); + } + } + } + + [Obsolete] + private static void ReadPackOptions(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec, ref bool isMappingsNull) + { + var wasMappingsRead = false; + bool isPackOptionsValueAnObject = false; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + isPackOptionsValueAnObject = true; + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(FilesPropertyName)) + { + wasMappingsRead = ReadPackOptionsFiles(packageSpec, ref jsonReader, wasMappingsRead); + } + else if (jsonReader.ValueTextEquals(IconUrlPropertyName)) + { + packageSpec.IconUrl = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(LicenseUrlPropertyName)) + { + packageSpec.LicenseUrl = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(OwnersPropertyName)) + { + jsonReader.Read(); + string[] owners = jsonReader.ReadStringArrayAsIList()?.ToArray(); + if (owners != null) + { + packageSpec.Owners = owners; + } + } + else if (jsonReader.ValueTextEquals(PackageTypePropertyName)) + { + ReadPackageTypes(packageSpec, ref jsonReader); + } + else if (jsonReader.ValueTextEquals(ProjectUrlPropertyName)) + { + packageSpec.ProjectUrl = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(ReleaseNotesPropertyName)) + { + packageSpec.ReleaseNotes = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(RequireLicenseAcceptancePropertyName)) + { + packageSpec.RequireLicenseAcceptance = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(SummaryPropertyName)) + { + packageSpec.Summary = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(TagsPropertyName)) + { + jsonReader.Read(); + string[] tags = jsonReader.ReadStringArrayAsIList()?.ToArray(); + + if (tags != null) + { + packageSpec.Tags = tags; + } + } + else + { + jsonReader.Skip(); + } + } + } + isMappingsNull = isPackOptionsValueAnObject && !wasMappingsRead; + } + + [Obsolete] + private static bool ReadPackOptionsFiles(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader, bool wasMappingsRead) + { + IReadOnlyList excludeFiles = null; + IReadOnlyList exclude = null; + IReadOnlyList includeFiles = null; + IReadOnlyList include = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(ExcludeFilesPropertyName)) + { + excludeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(ExcludePropertyName)) + { + exclude = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(IncludeFilesPropertyName)) + { + includeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(IncludePropertyName)) + { + include = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + else if (jsonReader.ValueTextEquals(MappingsPropertyName)) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + wasMappingsRead = true; + var mappingsPropertyName = jsonReader.GetString(); + ReadMappings(ref jsonReader, mappingsPropertyName, packageSpec.PackOptions.Mappings); + } + } + } + else + { + jsonReader.Skip(); + } + } + } + + if (include != null || includeFiles != null || exclude != null || excludeFiles != null) + { + packageSpec.PackOptions.IncludeExcludeFiles = new IncludeExcludeFiles() + { + ExcludeFiles = excludeFiles, + Exclude = exclude, + IncludeFiles = includeFiles, + Include = include + }; + } + + return wasMappingsRead; + } + + private static RuntimeDependencySet ReadRuntimeDependencySet(ref Utf8JsonStreamReader jsonReader, string dependencySetName) + { + List dependencies = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + dependencies ??= []; + + var dependency = new RuntimePackageDependency(propertyName, VersionRange.Parse(jsonReader.ReadNextTokenAsString())); + + dependencies.Add(dependency); + } + } + + return new RuntimeDependencySet( + dependencySetName, + dependencies); + } + + private static RuntimeDescription ReadRuntimeDescription(ref Utf8JsonStreamReader jsonReader, string runtimeName) + { + List inheritedRuntimes = null; + List additionalDependencies = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(HashTagImportPropertyName)) + { + jsonReader.Read(); + inheritedRuntimes = jsonReader.ReadStringArrayAsIList() as List; + } + else + { + var propertyName = jsonReader.GetString(); + additionalDependencies ??= []; + + RuntimeDependencySet dependency = ReadRuntimeDependencySet(ref jsonReader, propertyName); + + additionalDependencies.Add(dependency); + } + } + } + + return new RuntimeDescription( + runtimeName, + inheritedRuntimes, + additionalDependencies); + } + + private static List ReadRuntimes(ref Utf8JsonStreamReader jsonReader) + { + List runtimeDescriptions = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + RuntimeDescription runtimeDescription = ReadRuntimeDescription(ref jsonReader, jsonReader.GetString()); + runtimeDescriptions ??= []; + runtimeDescriptions.Add(runtimeDescription); + } + } + + return runtimeDescriptions; + } + + [Obsolete] + private static void ReadScripts(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + if (jsonReader.Read()) + { + if (jsonReader.TokenType == JsonTokenType.String) + { + packageSpec.Scripts[propertyName] = new string[] { (string)jsonReader.GetString() }; + } + else if (jsonReader.TokenType == JsonTokenType.StartArray) + { + IList list = null; + + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.String) + { + list ??= []; + list.Add(jsonReader.GetString()); + } + + packageSpec.Scripts[propertyName] = list ?? Enumerable.Empty(); + } + else + { + throw FileFormatException.Create( + string.Format(CultureInfo.CurrentCulture, "The value of a script in '{0}' can only be a string or an array of strings", PackageSpec.PackageSpecFileName), + packageSpec.FilePath); + } + } + } + } + } + + private static List ReadSupports(ref Utf8JsonStreamReader jsonReader) + { + List compatibilityProfiles = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = jsonReader.GetString(); + CompatibilityProfile compatibilityProfile = ReadCompatibilityProfile(ref jsonReader, propertyName); + compatibilityProfiles ??= []; + compatibilityProfiles.Add(compatibilityProfile); + } + } + return compatibilityProfiles; + } + + private static LibraryDependencyTarget ReadTarget( + ref Utf8JsonStreamReader jsonReader, + string packageSpecPath, + LibraryDependencyTarget targetFlagsValue) + { + if (jsonReader.Read()) + { + var targetString = jsonReader.GetString(); + + targetFlagsValue = LibraryDependencyTargetUtils.Parse(targetString); + + // Verify that the value specified is package, project, or external project +#pragma warning disable CS0612 // Type or member is obsolete + if (!ValidateDependencyTarget(targetFlagsValue)) + { + string message = string.Format( + CultureInfo.CurrentCulture, + Strings.InvalidDependencyTarget, + targetString); + throw FileFormatException.Create( + message, + packageSpecPath); + } +#pragma warning restore CS0612 // Type or member is obsolete + } + + return targetFlagsValue; + } + + private static List ReadTargetFrameworks(ref Utf8JsonStreamReader jsonReader) + { + List targetFrameworks = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var frameworkPropertyName = jsonReader.GetString(); + NuGetFramework framework = NuGetFramework.Parse(frameworkPropertyName); + var frameworkGroup = new ProjectRestoreMetadataFrameworkInfo(framework); + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(ProjectReferencesPropertyName)) + { + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + var projectReferencePropertyName = jsonReader.GetString(); + string excludeAssets = null; + string includeAssets = null; + string privateAssets = null; + string projectReferenceProjectPath = null; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(ExcludeAssetsPropertyName)) + { + excludeAssets = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(IncludeAssetsPropertyName)) + { + includeAssets = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(PrivateAssetsPropertyName)) + { + privateAssets = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(ProjectPathPropertyName)) + { + projectReferenceProjectPath = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + + } + } + + frameworkGroup.ProjectReferences.Add(new ProjectRestoreReference() + { + ProjectUniqueName = projectReferencePropertyName, + ProjectPath = projectReferenceProjectPath, + + IncludeAssets = LibraryIncludeFlagUtils.GetFlags( + flags: includeAssets, + defaultFlags: LibraryIncludeFlags.All), + + ExcludeAssets = LibraryIncludeFlagUtils.GetFlags( + flags: excludeAssets, + defaultFlags: LibraryIncludeFlags.None), + + PrivateAssets = LibraryIncludeFlagUtils.GetFlags( + flags: privateAssets, + defaultFlags: LibraryIncludeFlagUtils.DefaultSuppressParent), + }); + } + } + } + else if (jsonReader.ValueTextEquals(TargetAliasPropertyName)) + { + frameworkGroup.TargetAlias = jsonReader.ReadNextTokenAsString(); + } + else + { + jsonReader.Skip(); + } + } + targetFrameworks ??= []; + targetFrameworks.Add(frameworkGroup); + } + } + } + return targetFrameworks; + } + + private static void ReadTargetFrameworks(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader) + { + var frameworkName = NuGetFramework.Parse(jsonReader.GetString()); + + var targetFrameworkInformation = new TargetFrameworkInformation(); + NuGetFramework secondaryFramework = default; + + if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) + { + while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) + { + if (jsonReader.ValueTextEquals(AssetTargetFallbackPropertyName)) + { + targetFrameworkInformation.AssetTargetFallback = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else if (jsonReader.ValueTextEquals(SecondaryFrameworkPropertyName)) + { + var secondaryFrameworkString = jsonReader.ReadNextTokenAsString(); + if (!string.IsNullOrEmpty(secondaryFrameworkString)) + { + secondaryFramework = NuGetFramework.Parse(secondaryFrameworkString); + } + } + else if (jsonReader.ValueTextEquals(CentralPackageVersionsPropertyName)) + { + ReadCentralPackageVersions( + ref jsonReader, + targetFrameworkInformation.CentralPackageVersions, + packageSpec.FilePath); + } + else if (jsonReader.ValueTextEquals(DependenciesPropertyName)) + { + ReadDependencies( + ref jsonReader, + targetFrameworkInformation.Dependencies, + packageSpec.FilePath, + isGacOrFrameworkReference: false); + } + else if (jsonReader.ValueTextEquals(DownloadDependenciesPropertyName)) + { + ReadDownloadDependencies( + ref jsonReader, + targetFrameworkInformation.DownloadDependencies, + packageSpec.FilePath); + } + else if (jsonReader.ValueTextEquals(FrameworkAssembliesPropertyName)) + { + ReadDependencies( + ref jsonReader, + targetFrameworkInformation.Dependencies, + packageSpec.FilePath, + isGacOrFrameworkReference: true); + } + else if (jsonReader.ValueTextEquals(FrameworkReferencesPropertyName)) + { + ReadFrameworkReferences( + ref jsonReader, + targetFrameworkInformation.FrameworkReferences, + packageSpec.FilePath); + } + else if (jsonReader.ValueTextEquals(ImportsPropertyName)) + { + ReadImports(packageSpec, ref jsonReader, targetFrameworkInformation); + } + else if (jsonReader.ValueTextEquals(RuntimeIdentifierGraphPathPropertyName)) + { + targetFrameworkInformation.RuntimeIdentifierGraphPath = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(TargetAliasPropertyName)) + { + targetFrameworkInformation.TargetAlias = jsonReader.ReadNextTokenAsString(); + } + else if (jsonReader.ValueTextEquals(WarnPropertyName)) + { + targetFrameworkInformation.Warn = jsonReader.ReadNextTokenAsBoolOrFalse(); + } + else + { + jsonReader.Skip(); + } + } + } + +#pragma warning disable CS0612 // Type or member is obsolete + AddTargetFramework(packageSpec, frameworkName, secondaryFramework, targetFrameworkInformation); +#pragma warning restore CS0612 // Type or member is obsolete + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs index 95dfee38a35..26407bd7867 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs @@ -19,11 +19,11 @@ namespace NuGet.ProjectModel { - public static class JsonPackageSpecReader + public static partial class JsonPackageSpecReader { private static readonly char[] DelimitedStringSeparators = { ' ', ',' }; private static readonly char[] VersionSeparators = new[] { ';' }; - + private const char VersionSeparator = ';'; public static readonly string RestoreOptions = "restore"; public static readonly string RestoreSettings = "restoreSettings"; public static readonly string HideWarningsAndErrors = "hideWarningsAndErrors"; @@ -49,31 +49,52 @@ public static PackageSpec GetPackageSpec(string json, string name, string packag } } + public static PackageSpec GetPackageSpec(Stream stream, string name, string packageSpecPath, string snapshotValue) + { + return GetPackageSpec(stream, name, packageSpecPath, snapshotValue, EnvironmentVariableWrapper.Instance); + } + [Obsolete("This method is obsolete and will be removed in a future release.")] public static PackageSpec GetPackageSpec(JObject json) { return GetPackageSpec(json, name: null, packageSpecPath: null, snapshotValue: null); } - public static PackageSpec GetPackageSpec(Stream stream, string name, string packageSpecPath, string snapshotValue) + [Obsolete("This method is obsolete and will be removed in a future release.")] + public static PackageSpec GetPackageSpec(JObject rawPackageSpec, string name, string packageSpecPath, string snapshotValue) { - using (var streamReader = new StreamReader(stream)) - using (var jsonReader = new JsonTextReader(streamReader)) + using (var stringReader = new StringReader(rawPackageSpec.ToString())) + using (var jsonReader = new JsonTextReader(stringReader)) { return GetPackageSpec(jsonReader, name, packageSpecPath, EnvironmentVariableWrapper.Instance, snapshotValue); } } - [Obsolete("This method is obsolete and will be removed in a future release.")] - public static PackageSpec GetPackageSpec(JObject rawPackageSpec, string name, string packageSpecPath, string snapshotValue) + [Obsolete] + internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string packageSpecPath) { - using (var stringReader = new StringReader(rawPackageSpec.ToString())) - using (var jsonReader = new JsonTextReader(stringReader)) + return GetPackageSpec(jsonReader, name: null, packageSpecPath, EnvironmentVariableWrapper.Instance); + } + + internal static PackageSpec GetPackageSpec(Stream stream, string name, string packageSpecPath, string snapshotValue, IEnvironmentVariableReader environmentVariableReader, bool bypassCache = false) + { + if (!JsonUtility.UseNewtonsoftJsonForParsing(environmentVariableReader, bypassCache)) { - return GetPackageSpec(jsonReader, name, packageSpecPath, EnvironmentVariableWrapper.Instance, snapshotValue); + return GetPackageSpecUtf8JsonStreamReader(stream, name, packageSpecPath, environmentVariableReader, snapshotValue); + } + else + { + using (var textReader = new StreamReader(stream)) + using (var jsonReader = new JsonTextReader(textReader)) + { +#pragma warning disable CS0612 // Type or member is obsolete + return GetPackageSpec(jsonReader, name, packageSpecPath, environmentVariableReader, snapshotValue); +#pragma warning restore CS0612 // Type or member is obsolete + } } } + [Obsolete] internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string name, string packageSpecPath, IEnvironmentVariableReader environmentVariableReader, string snapshotValue = null) { var packageSpec = new PackageSpec(); @@ -232,6 +253,7 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam return packageSpec; } + [Obsolete] private static PackageType CreatePackageType(JsonTextReader jsonReader) { var name = (string)jsonReader.Value; @@ -253,6 +275,7 @@ private static void ReadBuildOptions(JsonTextReader jsonReader, PackageSpec pack }); } + [Obsolete] private static void ReadCentralPackageVersions( JsonTextReader jsonReader, IDictionary centralPackageVersions, @@ -287,6 +310,7 @@ private static void ReadCentralPackageVersions( }); } + [Obsolete] private static CompatibilityProfile ReadCompatibilityProfile(JsonTextReader jsonReader, string profileName) { List sets = null; @@ -303,6 +327,7 @@ private static CompatibilityProfile ReadCompatibilityProfile(JsonTextReader json return new CompatibilityProfile(profileName, sets ?? Enumerable.Empty()); } + [Obsolete] private static IEnumerable ReadCompatibilitySets(JsonTextReader jsonReader, string compatibilitySetName) { NuGetFramework framework = NuGetFramework.Parse(compatibilitySetName); @@ -315,7 +340,8 @@ private static IEnumerable ReadCompatibilitySets(JsonTextR } } - internal static void ReadDependencies( + [Obsolete] + private static void ReadDependencies( JsonTextReader jsonReader, IList results, string packageSpecPath, @@ -509,6 +535,7 @@ internal static void ReadDependencies( }); } + [Obsolete] internal static void ReadCentralTransitiveDependencyGroup( JsonTextReader jsonReader, IList results, @@ -631,6 +658,7 @@ internal static void ReadCentralTransitiveDependencyGroup( }); } + [Obsolete] private static void ReadDownloadDependencies( JsonTextReader jsonReader, IList downloadDependencies, @@ -721,6 +749,7 @@ private static void ReadDownloadDependencies( } } + [Obsolete] private static IReadOnlyList ReadEnumerableOfString(JsonTextReader jsonReader) { string value = jsonReader.ReadNextTokenAsString(); @@ -728,6 +757,7 @@ private static IReadOnlyList ReadEnumerableOfString(JsonTextReader jsonR return value.Split(DelimitedStringSeparators, StringSplitOptions.RemoveEmptyEntries); } + [Obsolete] private static void ReadFrameworkReferences( JsonTextReader jsonReader, ISet frameworkReferences, @@ -763,6 +793,7 @@ private static void ReadFrameworkReferences( }); } + [Obsolete] private static void ReadFrameworks(JsonTextReader jsonReader, PackageSpec packageSpec) { jsonReader.ReadObject(_ => @@ -781,6 +812,7 @@ private static void ReadFrameworks(JsonTextReader jsonReader, PackageSpec packag }); } + [Obsolete] private static void ReadImports(PackageSpec packageSpec, JsonTextReader jsonReader, TargetFrameworkInformation targetFrameworkInformation) { int lineNumber = jsonReader.LineNumber; @@ -812,6 +844,7 @@ private static void ReadImports(PackageSpec packageSpec, JsonTextReader jsonRead } } + [Obsolete] private static void ReadMappings(JsonTextReader jsonReader, string mappingKey, IDictionary mappings) { if (jsonReader.ReadNextToken()) @@ -889,6 +922,7 @@ private static void ReadMappings(JsonTextReader jsonReader, string mappingKey, I } } + [Obsolete] private static void ReadMSBuildMetadata(JsonTextReader jsonReader, PackageSpec packageSpec, IEnvironmentVariableReader environmentVariableReader) { var centralPackageVersionsManagementEnabled = false; @@ -1233,6 +1267,7 @@ private static bool ReadNextTokenAsBoolOrFalse(JsonTextReader jsonReader, string return false; } + [Obsolete] private static void ReadNuGetLogCodes(JsonTextReader jsonReader, HashSet hashCodes) { if (jsonReader.ReadNextToken() && jsonReader.TokenType == JsonToken.StartArray) @@ -1267,6 +1302,7 @@ private static IList ReadNuGetLogCodesList(JsonTextReader jsonRead return items ?? Array.Empty(); } + [Obsolete] private static void ReadPackageTypes(PackageSpec packageSpec, JsonTextReader jsonReader) { var errorLine = 0; @@ -1471,7 +1507,8 @@ private static bool ReadPackOptionsFiles(PackageSpec packageSpec, JsonTextReader return wasMappingsRead; } - private static RuntimeDependencySet ReadRuntimeDependencySet(JsonTextReader jsonReader, string dependencySetName) + [Obsolete] + static RuntimeDependencySet ReadRuntimeDependencySet(JsonTextReader jsonReader, string dependencySetName) { List dependencies = null; @@ -1489,6 +1526,7 @@ private static RuntimeDependencySet ReadRuntimeDependencySet(JsonTextReader json dependencies); } + [Obsolete] private static RuntimeDescription ReadRuntimeDescription(JsonTextReader jsonReader, string runtimeName) { List inheritedRuntimes = null; @@ -1516,6 +1554,7 @@ private static RuntimeDescription ReadRuntimeDescription(JsonTextReader jsonRead additionalDependencies); } + [Obsolete] private static List ReadRuntimes(JsonTextReader jsonReader) { var runtimeDescriptions = new List(); @@ -1564,6 +1603,7 @@ private static void ReadScripts(JsonTextReader jsonReader, PackageSpec packageSp }); } + [Obsolete] private static string[] ReadStringArray(JsonTextReader jsonReader) { List list = jsonReader.ReadStringArrayAsList(); @@ -1571,6 +1611,7 @@ private static string[] ReadStringArray(JsonTextReader jsonReader) return list?.ToArray(); } + [Obsolete] private static List ReadSupports(JsonTextReader jsonReader) { var compatibilityProfiles = new List(); @@ -1585,6 +1626,7 @@ private static List ReadSupports(JsonTextReader jsonReader return compatibilityProfiles; } + [Obsolete] private static LibraryDependencyTarget ReadTarget( JsonTextReader jsonReader, string packageSpecPath, @@ -1615,6 +1657,7 @@ private static LibraryDependencyTarget ReadTarget( return targetFlagsValue; } + [Obsolete] private static List ReadTargetFrameworks(JsonTextReader jsonReader) { var targetFrameworks = new List(); @@ -1688,6 +1731,7 @@ private static List ReadTargetFrameworks(Js return targetFrameworks; } + [Obsolete] private static void ReadTargetFrameworks(PackageSpec packageSpec, JsonTextReader jsonReader, out int frameworkLine, out int frameworkColumn) { frameworkLine = 0; @@ -1768,6 +1812,12 @@ private static void ReadTargetFrameworks(PackageSpec packageSpec, JsonTextReader } }, out frameworkLine, out frameworkColumn); + AddTargetFramework(packageSpec, frameworkName, secondaryFramework, targetFrameworkInformation); + } + + [Obsolete] + private static void AddTargetFramework(PackageSpec packageSpec, NuGetFramework frameworkName, NuGetFramework secondaryFramework, TargetFrameworkInformation targetFrameworkInformation) + { NuGetFramework updatedFramework = frameworkName; if (targetFrameworkInformation.Imports.Count > 0) @@ -1793,6 +1843,8 @@ private static void ReadTargetFrameworks(PackageSpec packageSpec, JsonTextReader packageSpec.TargetFrameworks.Add(targetFrameworkInformation); } + + [Obsolete] private static NuGetFramework GetDualCompatibilityFrameworkIfNeeded(NuGetFramework frameworkName, NuGetFramework secondaryFramework) { if (secondaryFramework != default) @@ -1803,6 +1855,7 @@ private static NuGetFramework GetDualCompatibilityFrameworkIfNeeded(NuGetFramewo return frameworkName; } + [Obsolete] private static bool ValidateDependencyTarget(LibraryDependencyTarget targetValue) { var isValid = false; diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs index 742629ad4b5..4de5162b05c 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs @@ -6,6 +6,7 @@ using System.IO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using NuGet.Common; using NuGet.Packaging.Core; using NuGet.Versioning; @@ -13,6 +14,8 @@ namespace NuGet.ProjectModel { internal static class JsonUtility { + internal static string NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING = nameof(NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING); + internal static bool? UseNewtonsoftJson = null; internal static readonly char[] PathSplitChars = new[] { LockFile.DirectorySeparatorChar }; /// @@ -43,6 +46,12 @@ internal static JObject LoadJson(TextReader reader) } } + internal static T LoadJson(Stream stream, IUtf8JsonStreamReaderConverter converter) + { + var streamingJsonReader = new Utf8JsonStreamReader(stream); + return converter.Read(ref streamingJsonReader); + } + internal static PackageDependency ReadPackageDependency(string property, JToken json) { var versionStr = json.Value(); @@ -51,6 +60,23 @@ internal static PackageDependency ReadPackageDependency(string property, JToken versionStr == null ? null : VersionRange.Parse(versionStr)); } + internal static bool UseNewtonsoftJsonForParsing(IEnvironmentVariableReader environmentVariableReader, bool bypassCache) + { + if (!UseNewtonsoftJson.HasValue || bypassCache) + { + if (bool.TryParse(environmentVariableReader.GetEnvironmentVariable(NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING), out var useNj)) + { + UseNewtonsoftJson = useNj; + } + else + { + UseNewtonsoftJson = false; + } + } + + return UseNewtonsoftJson.Value; + } + internal static JProperty WritePackageDependencyWithLegacyString(PackageDependency item) { return new JProperty( diff --git a/src/NuGet.Core/NuGet.ProjectModel/LazyStringSplit.cs b/src/NuGet.Core/NuGet.ProjectModel/LazyStringSplit.cs new file mode 100644 index 00000000000..6ccb0f3fc9c --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LazyStringSplit.cs @@ -0,0 +1,138 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace NuGet.ProjectModel +{ + /// + /// Splits a string by a delimiter, producing substrings lazily during enumeration. + /// Skips empty items, behaving equivalently to with + /// . + /// + /// + /// Unlike and overloads, + /// does not allocate an array for the return, and allocates strings on demand during + /// enumeration. A custom enumerator type is used so that the only allocations made are + /// the substrings themselves. We also avoid the large internal arrays assigned by the + /// methods on . + /// + internal readonly struct LazyStringSplit : IEnumerable + { + private readonly string _input; + private readonly char _delimiter; + + public LazyStringSplit(string input, char delimiter) + { + if (input is null) + { + throw new ArgumentNullException(nameof(input)); + } + + _input = input; + _delimiter = delimiter; + } + + public Enumerator GetEnumerator() => new(this); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public IEnumerable Select(Func func) + { + foreach (string value in this) + { + yield return func(value); + } + } + + public string First() + { + return FirstOrDefault() ?? throw new InvalidOperationException("Sequence is empty."); + } + + public string? FirstOrDefault() + { + var enumerator = new Enumerator(this); + return enumerator.MoveNext() ? enumerator.Current : null; + } + + public struct Enumerator : IEnumerator + { + private readonly string _input; + private readonly char _delimiter; + private int _index; + + internal Enumerator(in LazyStringSplit split) + { + _index = 0; + _input = split._input; + _delimiter = split._delimiter; + Current = null!; + } + + public string Current { get; private set; } + + public bool MoveNext() + { + while (_index != _input.Length) + { + int delimiterIndex = _input.IndexOf(_delimiter, _index); + + if (delimiterIndex == -1) + { + Current = _input.Substring(_index); + _index = _input.Length; + return true; + } + + int length = delimiterIndex - _index; + + if (length == 0) + { + _index++; + continue; + } + + Current = _input.Substring(_index, length); + _index = delimiterIndex + 1; + return true; + } + + return false; + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _index = 0; + Current = null!; + } + + void IDisposable.Dispose() { } + } + } + + internal static class LazyStringSplitExtensions + { + /// + /// This extension method has special knowledge of the type and + /// can compute its result without allocation. + /// + /// + public static string? FirstOrDefault(this LazyStringSplit lazyStringSplit) + { + LazyStringSplit.Enumerator enumerator = lazyStringSplit.GetEnumerator(); + + return enumerator.MoveNext() + ? enumerator.Current + : null; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs index d327afa0e74..83c5bfd8116 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NuGet.Common; @@ -60,9 +61,10 @@ public LockFile Parse(string lockFileContent, string path) public LockFile Parse(string lockFileContent, ILogger log, string path) { - using (var reader = new StringReader(lockFileContent)) + byte[] byteArray = Encoding.UTF8.GetBytes(lockFileContent); + using (var stream = new MemoryStream(byteArray)) { - return Read(reader, log, path); + return Read(stream, log, path); } } @@ -86,17 +88,33 @@ public LockFile Read(Stream stream, string path) public LockFile Read(Stream stream, ILogger log, string path) { - using (var textReader = new StreamReader(stream)) + return Read(stream, log, path, EnvironmentVariableWrapper.Instance); + } + + internal LockFile Read(Stream stream, ILogger log, string path, IEnvironmentVariableReader environmentVariableReader, bool bypassCache = false) + { + if (!JsonUtility.UseNewtonsoftJsonForParsing(environmentVariableReader, bypassCache)) { - return Read(textReader, log, path); + return Utf8JsonRead(stream, log, path); + } + else + { + using (var reader = new StreamReader(stream)) + { +#pragma warning disable CS0618 // Type or member is obsolete + return Read(reader, log, path); +#pragma warning restore CS0618 // Type or member is obsolete + } } } + [Obsolete("This method is deprecated. Use Read(Stream, string) instead.")] public LockFile Read(TextReader reader, string path) { return Read(reader, NullLogger.Instance, path); } + [Obsolete("This method is deprecated. Use Read(Stream, ILogger, string) instead.")] public LockFile Read(TextReader reader, ILogger log, string path) { try @@ -161,6 +179,30 @@ public string Render(LockFile lockFile) } } + private LockFile Utf8JsonRead(Stream stream, ILogger log, string path) + { + try + { + var lockFile = JsonUtility.LoadJson(stream, Utf8JsonReaderExtensions.LockFileConverter); + lockFile.Path = path; + return lockFile; + } + catch (Exception ex) + { + log.LogInformation(string.Format(CultureInfo.CurrentCulture, + Strings.Log_ErrorReadingLockFile, + path, ex.Message)); + + // Ran into parsing errors, mark it as unlocked and out-of-date + return new LockFile + { + Version = int.MinValue, + Path = path + }; + } + } + + [Obsolete] private static LockFile ReadLockFile(JObject cursor, string path) { var lockFile = new LockFile() @@ -915,6 +957,7 @@ private static void WriteCentralTransitiveDependencyGroup(IObjectWriter writer, writer.WriteObjectEnd(); } + [Obsolete] private static List ReadProjectFileTransitiveDependencyGroup(JObject json, string path) { var results = new List(); diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamIAssetsLogMessageConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamIAssetsLogMessageConverter.cs new file mode 100644 index 00000000000..30ff0ad1c00 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamIAssetsLogMessageConverter.cs @@ -0,0 +1,148 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using NuGet.Common; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// { + /// "code": "", + /// "level": "", + /// "message": "test log message", + /// "warningLevel": , + /// "filePath": "C:\a\file\path.txt", + /// "startLineNumber": 1, + /// "startColumnNumber": 2, + /// "endLineNumber": 10, + /// "endcolumnNumber": 20, + /// "libraryId": "libraryId", + /// "targetGraphs": [ + /// "targetGraph1" + /// ] + /// } + /// + internal class Utf8JsonStreamIAssetsLogMessageConverter : IUtf8JsonStreamReaderConverter + { + private static readonly byte[] LevelPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.LEVEL); + private static readonly byte[] CodePropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.CODE); + private static readonly byte[] WarningLevelPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.WARNING_LEVEL); + private static readonly byte[] FilePathPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.FILE_PATH); + private static readonly byte[] StartLineNumberPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.START_LINE_NUMBER); + private static readonly byte[] StartColumnNumberPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.START_COLUMN_NUMBER); + private static readonly byte[] EndLineNumberPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.END_LINE_NUMBER); + private static readonly byte[] EndColumnNumberPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.END_COLUMN_NUMBER); + private static readonly byte[] MessagePropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.MESSAGE); + private static readonly byte[] LibraryIdPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.LIBRARY_ID); + private static readonly byte[] TargetGraphsPropertyName = Encoding.UTF8.GetBytes(LogMessageProperties.TARGET_GRAPHS); + + public IAssetsLogMessage Read(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected StartObject, found " + reader.TokenType); + } + + var isValid = true; + LogLevel level = default; + NuGetLogCode code = default; + //matching default warning level when AssetLogMessage object is created + WarningLevel warningLevel = WarningLevel.Severe; + string message = default; + string filePath = default; + int startLineNumber = default; + int startColNumber = default; + int endLineNumber = default; + int endColNumber = default; + string libraryId = default; + IReadOnlyList targetGraphs = null; + + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + if (!isValid) + { + reader.Skip(); + } + if (reader.ValueTextEquals(LevelPropertyName)) + { + var levelString = reader.ReadNextTokenAsString(); + isValid &= Enum.TryParse(levelString, out level); + } + else if (reader.ValueTextEquals(CodePropertyName)) + { + var codeString = reader.ReadNextTokenAsString(); + isValid &= Enum.TryParse(codeString, out code); + } + else if (reader.ValueTextEquals(WarningLevelPropertyName)) + { + reader.Read(); + warningLevel = (WarningLevel)Enum.ToObject(typeof(WarningLevel), reader.GetInt32()); + } + else if (reader.ValueTextEquals(FilePathPropertyName)) + { + filePath = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(StartLineNumberPropertyName)) + { + reader.Read(); + startLineNumber = reader.GetInt32(); + } + else if (reader.ValueTextEquals(StartColumnNumberPropertyName)) + { + reader.Read(); + startColNumber = reader.GetInt32(); + } + else if (reader.ValueTextEquals(EndLineNumberPropertyName)) + { + reader.Read(); + endLineNumber = reader.GetInt32(); + } + else if (reader.ValueTextEquals(EndColumnNumberPropertyName)) + { + reader.Read(); + endColNumber = reader.GetInt32(); + } + else if (reader.ValueTextEquals(MessagePropertyName)) + { + message = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(LibraryIdPropertyName)) + { + libraryId = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(TargetGraphsPropertyName)) + { + reader.Read(); + targetGraphs = (List)reader.ReadStringArrayAsIList(); + } + else + { + reader.Skip(); + } + } + if (isValid) + { + var assetLogMessage = new AssetsLogMessage(level, code, message) + { + TargetGraphs = targetGraphs ?? Array.Empty(), + FilePath = filePath, + EndColumnNumber = endColNumber, + EndLineNumber = endLineNumber, + LibraryId = libraryId, + StartColumnNumber = startColNumber, + StartLineNumber = startLineNumber, + WarningLevel = warningLevel + }; + return assetLogMessage; + } + return null; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileConverter.cs new file mode 100644 index 00000000000..859f388a762 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileConverter.cs @@ -0,0 +1,136 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using NuGet.Common; +using NuGet.Frameworks; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// { + /// "version": 3, + /// "targets": { }, + /// "libraries": { }, + /// "projectFileDependencyGroups": { }, + /// "packageFolders": { }, + /// "project": { }, + /// "logs": [ ] + /// } + /// + internal class Utf8JsonStreamLockFileConverter : IUtf8JsonStreamReaderConverter + { + private static readonly byte[] VersionPropertyName = Encoding.UTF8.GetBytes("version"); + private static readonly byte[] LibrariesPropertyName = Encoding.UTF8.GetBytes("libraries"); + private static readonly byte[] TargetsPropertyName = Encoding.UTF8.GetBytes("targets"); + private static readonly byte[] ProjectFileDependencyGroupsPropertyName = Encoding.UTF8.GetBytes("projectFileDependencyGroups"); + private static readonly byte[] PackageFoldersPropertyName = Encoding.UTF8.GetBytes("packageFolders"); + private static readonly byte[] ProjectPropertyName = Encoding.UTF8.GetBytes("project"); + private static readonly byte[] CentralTransitiveDependencyGroupsPropertyName = Encoding.UTF8.GetBytes("centralTransitiveDependencyGroups"); + private static readonly byte[] LogsPropertyName = Encoding.UTF8.GetBytes("logs"); + + public LockFile Read(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected StartObject, found " + reader.TokenType); + } + + var lockFile = new LockFile(); + + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + if (reader.ValueTextEquals(VersionPropertyName)) + { + reader.Read(); + if (reader.TryGetInt32(out int version)) + { + lockFile.Version = version; + } + else + { + lockFile.Version = int.MinValue; + } + } + else if (reader.ValueTextEquals(LibrariesPropertyName)) + { + reader.Read(); + lockFile.Libraries = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileLibraryConverter); + } + else if (reader.ValueTextEquals(TargetsPropertyName)) + { + reader.Read(); + lockFile.Targets = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileTargetConverter); + } + else if (reader.ValueTextEquals(ProjectFileDependencyGroupsPropertyName)) + { + reader.Read(); + lockFile.ProjectFileDependencyGroups = reader.ReadObjectAsList(Utf8JsonReaderExtensions.ProjectFileDepencencyGroupConverter); + } + else if (reader.ValueTextEquals(PackageFoldersPropertyName)) + { + reader.Read(); + lockFile.PackageFolders = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(ProjectPropertyName)) + { + reader.Read(); + lockFile.PackageSpec = JsonPackageSpecReader.GetPackageSpec( + ref reader, + name: null, + packageSpecPath: null, + EnvironmentVariableWrapper.Instance, + snapshotValue: null); + } + else if (reader.ValueTextEquals(CentralTransitiveDependencyGroupsPropertyName)) + { + IList results = null; + if (reader.Read() && reader.TokenType == JsonTokenType.StartObject) + { + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + results ??= new List(); + var frameworkPropertyName = reader.GetString(); + NuGetFramework framework = NuGetFramework.Parse(frameworkPropertyName); + + JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( + jsonReader: ref reader, + results: out var dependencies, + packageSpecPath: string.Empty); + results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + } + } + lockFile.CentralTransitiveDependencyGroups = results ?? Array.Empty(); + } + else if (reader.ValueTextEquals(LogsPropertyName)) + { + reader.Read(); + lockFile.LogMessages = reader.ReadListOfObjects(Utf8JsonReaderExtensions.IAssetsLogMessageConverter); + } + else + { + reader.Skip(); + } + } + + var projectPath = lockFile.PackageSpec?.RestoreMetadata?.ProjectPath; + if (!string.IsNullOrEmpty(projectPath) && lockFile.LogMessages.Count > 0) + { + foreach (AssetsLogMessage message in lockFile.LogMessages.Where(x => string.IsNullOrEmpty(x.ProjectPath))) + { + message.ProjectPath = projectPath; + message.FilePath = projectPath; + } + } + + return lockFile; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileItemConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileItemConverter.cs new file mode 100644 index 00000000000..9a2ce569db0 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileItemConverter.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text.Json; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// "path/to/the.dll": { + /// "property1": "val1", + /// "property2": 2 + /// "property3": true + /// "property4": false + /// } + /// + internal class Utf8JsonStreamLockFileItemConverter : IUtf8JsonStreamReaderConverter where T : LockFileItem + { + private Func _lockFileItemCreator; + + public Utf8JsonStreamLockFileItemConverter(Func lockFileItemCreator) + { + _lockFileItemCreator = lockFileItemCreator; + } + + public T Read(ref Utf8JsonStreamReader reader) + { + var genericType = typeof(T); + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName, found " + reader.TokenType); + } + + //We want to read the property name right away + var lockItemPath = reader.GetString(); + LockFileItem lockFileItem = _lockFileItemCreator(lockItemPath); + + reader.Read(); + if (reader.TokenType == JsonTokenType.StartObject) + { + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = reader.GetString(); + lockFileItem.Properties[propertyName] = reader.ReadNextTokenAsString(); + } + } + + return lockFileItem as T; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs new file mode 100644 index 00000000000..43006240f4a --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs @@ -0,0 +1,102 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Text; +using System.Text.Json; +using NuGet.Versioning; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// "PackageA/1.0.0": { + /// "sha512": "ASha512", + /// "type": "package", + /// "path": "C:\a\test\path", + /// "files": [ + /// "PackageA.nuspec", + /// "lib/netstandard2.0/PackageA.dll" + /// ], + /// "msbuildProject": "bar", + /// "servicable": true, + /// "hasTools": true, + /// } + /// + internal class Utf8JsonStreamLockFileLibraryConverter : IUtf8JsonStreamReaderConverter + { + private static readonly byte[] Sha512PropertyName = Encoding.UTF8.GetBytes("sha512"); + private static readonly byte[] TypePropertyName = Encoding.UTF8.GetBytes("type"); + private static readonly byte[] PathPropertyName = Encoding.UTF8.GetBytes("path"); + private static readonly byte[] MsbuildProjectPropertyName = Encoding.UTF8.GetBytes("msbuildProject"); + private static readonly byte[] ServicablePropertyName = Encoding.UTF8.GetBytes("servicable"); + private static readonly byte[] HasToolsPropertyName = Encoding.UTF8.GetBytes("hasTools"); + private static readonly byte[] FilesPropertyName = Encoding.UTF8.GetBytes("files"); + + public LockFileLibrary Read(ref Utf8JsonStreamReader reader) + { + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName, found " + reader.TokenType); + } + + var lockFileLibrary = new LockFileLibrary(); + //We want to read the property name right away + var propertyName = reader.GetString(); + var (name, version) = propertyName.SplitInTwo(LockFile.DirectorySeparatorChar); + lockFileLibrary.Name = name; + if (!string.IsNullOrWhiteSpace(version)) + { + lockFileLibrary.Version = NuGetVersion.Parse(version); + } + + reader.Read(); + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected StartObject, found " + reader.TokenType); + } + + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + if (reader.ValueTextEquals(TypePropertyName)) + { + lockFileLibrary.Type = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(PathPropertyName)) + { + lockFileLibrary.Path = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(MsbuildProjectPropertyName)) + { + lockFileLibrary.MSBuildProject = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(Sha512PropertyName)) + { + lockFileLibrary.Sha512 = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(ServicablePropertyName)) + { + reader.Read(); + lockFileLibrary.IsServiceable = reader.GetBoolean(); + } + else if (reader.ValueTextEquals(HasToolsPropertyName)) + { + reader.Read(); + lockFileLibrary.HasTools = reader.GetBoolean(); + } + else if (reader.ValueTextEquals(FilesPropertyName)) + { + reader.Read(); + reader.ReadStringArrayAsIList(lockFileLibrary.Files); + } + else + { + reader.Skip(); + } + } + return lockFileLibrary; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetConverter.cs new file mode 100644 index 00000000000..1de4e0de65f --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetConverter.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Text.Json; +using NuGet.Frameworks; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// "net45/win8": { + /// , + /// } + /// + internal class Utf8JsonStreamLockFileTargetConverter : IUtf8JsonStreamReaderConverter + { + public LockFileTarget Read(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName, found " + reader.TokenType); + } + + var lockFileTarget = new LockFileTarget(); + //We want to read the property name right away + var propertyName = reader.GetString(); + var (targetFramework, runTimeFramework) = propertyName.SplitInTwo(LockFile.DirectorySeparatorChar); + + lockFileTarget.TargetFramework = NuGetFramework.Parse(targetFramework); + lockFileTarget.RuntimeIdentifier = runTimeFramework; + + reader.Read(); + lockFileTarget.Libraries = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileTargetLibraryConverter); + + return lockFileTarget; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs new file mode 100644 index 00000000000..4f88c3d0dcc --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs @@ -0,0 +1,195 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using NuGet.Packaging.Core; +using NuGet.Versioning; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow read JSON into + /// + /// + /// "Lirbary/1.0.0": { + /// "type": "package", + /// "framework": ".NETCoreApp,Version=v6.0", + /// "dependencies": { + /// "Library.Name": "1.0.1", + /// "Parser.Json": "10.0.0", + /// }, + /// "frameworkAssemblies": [ + /// "System" + /// ], + /// "compile": { + /// , + /// }, + /// "runtime": { + /// , + /// }, + /// "resource": { + /// , + /// }, + /// "contentFiles": { + /// , + /// }, + /// "runtimeTargets": { + /// , + /// }, + /// "tools": { + /// , + /// }, + /// "embed": { + /// , + /// }, + /// "frameworkReferences": [ + /// "Framework1", + /// ] + /// } + /// + internal class Utf8JsonStreamLockFileTargetLibraryConverter : IUtf8JsonStreamReaderConverter + { + private static readonly byte[] TypePropertyName = Encoding.UTF8.GetBytes("type"); + private static readonly byte[] FrameworkPropertyName = Encoding.UTF8.GetBytes("framework"); + private static readonly byte[] DependenciesPropertyName = Encoding.UTF8.GetBytes("dependencies"); + private static readonly byte[] FrameworkAssembliesPropertyName = Encoding.UTF8.GetBytes("frameworkAssemblies"); + private static readonly byte[] RuntimePropertyName = Encoding.UTF8.GetBytes("runtime"); + private static readonly byte[] CompilePropertyName = Encoding.UTF8.GetBytes("compile"); + private static readonly byte[] ResourcePropertyName = Encoding.UTF8.GetBytes("resource"); + private static readonly byte[] NativePropertyName = Encoding.UTF8.GetBytes("native"); + private static readonly byte[] BuildPropertyName = Encoding.UTF8.GetBytes("build"); + private static readonly byte[] BuildMultiTargetingPropertyName = Encoding.UTF8.GetBytes("buildMultiTargeting"); + private static readonly byte[] ContentFilesPropertyName = Encoding.UTF8.GetBytes("contentFiles"); + private static readonly byte[] RuntimeTargetsPropertyName = Encoding.UTF8.GetBytes("runtimeTargets"); + private static readonly byte[] ToolsPropertyName = Encoding.UTF8.GetBytes("tools"); + private static readonly byte[] EmbedPropertyName = Encoding.UTF8.GetBytes("embed"); + private static readonly byte[] FrameworkReferencesPropertyName = Encoding.UTF8.GetBytes("frameworkReferences"); + + public LockFileTargetLibrary Read(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName, found " + reader.TokenType); + } + + var lockFileTargetLibrary = new LockFileTargetLibrary(); + + //We want to read the property name right away + var propertyName = reader.GetString(); + var (targetLibraryName, version) = propertyName.SplitInTwo('/'); + lockFileTargetLibrary.Name = targetLibraryName; + lockFileTargetLibrary.Version = version is null ? null : NuGetVersion.Parse(version); + + reader.Read(); + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected StartObject, found " + reader.TokenType); + } + + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + if (reader.ValueTextEquals(TypePropertyName)) + { + lockFileTargetLibrary.Type = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(FrameworkPropertyName)) + { + lockFileTargetLibrary.Framework = reader.ReadNextTokenAsString(); + } + else if (reader.ValueTextEquals(DependenciesPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.Dependencies = ReadPackageDependencyList(ref reader); + } + else if (reader.ValueTextEquals(FrameworkAssembliesPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.FrameworkAssemblies = reader.ReadStringArrayAsIList() ?? Array.Empty(); + } + else if (reader.ValueTextEquals(RuntimePropertyName)) + { + reader.Read(); + lockFileTargetLibrary.RuntimeAssemblies = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(CompilePropertyName)) + { + reader.Read(); + lockFileTargetLibrary.CompileTimeAssemblies = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(ResourcePropertyName)) + { + reader.Read(); + lockFileTargetLibrary.ResourceAssemblies = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(NativePropertyName)) + { + reader.Read(); + lockFileTargetLibrary.NativeLibraries = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(BuildPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.Build = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(BuildMultiTargetingPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.BuildMultiTargeting = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(ContentFilesPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.ContentFiles = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileContentFileConverter); + } + else if (reader.ValueTextEquals(RuntimeTargetsPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.RuntimeTargets = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileRuntimeTargetConverter); + } + else if (reader.ValueTextEquals(ToolsPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.ToolsAssemblies = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(EmbedPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.EmbedAssemblies = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + else if (reader.ValueTextEquals(FrameworkReferencesPropertyName)) + { + reader.Read(); + lockFileTargetLibrary.FrameworkReferences = reader.ReadStringArrayAsIList(); + } + else + { + reader.Skip(); + } + } + lockFileTargetLibrary.Freeze(); + return lockFileTargetLibrary; + } + + private IList ReadPackageDependencyList(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + return Array.Empty(); + } + + var packageDependencies = new List(10); + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + string propertyName = reader.GetString(); + string versionString = reader.ReadNextTokenAsString(); + packageDependencies.Add(new PackageDependency( + propertyName, + versionString == null ? null : VersionRange.Parse(versionString))); + } + return packageDependencies; + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/StringExtensions.cs b/src/NuGet.Core/NuGet.ProjectModel/StringExtensions.cs new file mode 100644 index 00000000000..925bda42fd2 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/StringExtensions.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#nullable enable + +using System.Globalization; + +namespace NuGet.ProjectModel +{ + internal static class StringExtensions + { + internal static (string firstPart, string? secondPart) SplitInTwo(this string s, char separator) + { + if (string.IsNullOrEmpty(s)) + { + return (s, null); + } + var index = CultureInfo.CurrentCulture.CompareInfo.IndexOf(s, separator, CompareOptions.Ordinal); + + if (index == -1) + { + return (s, null); + } + + return (s.Substring(0, index), + index >= s.Length - 1 ? + null : + s.Substring(index + 1)); + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonReaderExtensions.cs b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonReaderExtensions.cs new file mode 100644 index 00000000000..bf53c40bba2 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonReaderExtensions.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text.Json; + +namespace NuGet.ProjectModel +{ + internal static class Utf8JsonReaderExtensions + { + internal static readonly Utf8JsonStreamLockFileConverter LockFileConverter = new Utf8JsonStreamLockFileConverter(); + internal static readonly Utf8JsonStreamLockFileItemConverter LockFileItemConverter = new Utf8JsonStreamLockFileItemConverter((string filePath) => new LockFileItem(filePath)); + internal static readonly Utf8JsonStreamLockFileItemConverter LockFileContentFileConverter = new Utf8JsonStreamLockFileItemConverter((string filePath) => new LockFileContentFile(filePath)); + internal static readonly Utf8JsonStreamLockFileItemConverter LockFileRuntimeTargetConverter = new Utf8JsonStreamLockFileItemConverter((string filePath) => new LockFileRuntimeTarget(filePath)); + internal static readonly Utf8JsonStreamLockFileTargetLibraryConverter LockFileTargetLibraryConverter = new Utf8JsonStreamLockFileTargetLibraryConverter(); + internal static readonly Utf8JsonStreamLockFileLibraryConverter LockFileLibraryConverter = new Utf8JsonStreamLockFileLibraryConverter(); + internal static readonly Utf8JsonStreamLockFileTargetConverter LockFileTargetConverter = new Utf8JsonStreamLockFileTargetConverter(); + internal static readonly Utf8JsonStreamProjectFileDependencyGroupConverter ProjectFileDepencencyGroupConverter = new Utf8JsonStreamProjectFileDependencyGroupConverter(); + internal static readonly Utf8JsonStreamIAssetsLogMessageConverter IAssetsLogMessageConverter = new Utf8JsonStreamIAssetsLogMessageConverter(); + + + internal static string ReadTokenAsString(this ref Utf8JsonReader reader) + { + switch (reader.TokenType) + { + case JsonTokenType.True: + return bool.TrueString; + case JsonTokenType.False: + return bool.FalseString; + case JsonTokenType.Number: + return reader.ReadNumberAsString(); + case JsonTokenType.String: + return reader.GetString(); + case JsonTokenType.None: + case JsonTokenType.Null: + return null; + default: + throw new InvalidCastException(); + } + } + + private static string ReadNumberAsString(this ref Utf8JsonReader reader) + { + if (reader.TryGetInt64(out long value)) + { + return value.ToString(); + } + return reader.GetDouble().ToString(); + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamProjectFileDependencyGroupConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamProjectFileDependencyGroupConverter.cs new file mode 100644 index 00000000000..b452497341a --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamProjectFileDependencyGroupConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text.Json; + +namespace NuGet.ProjectModel +{ + /// + /// A to allow reading JSON into + /// + /// + /// "net45": [ + /// "Json.Parser (>= 1.0.1)", + /// ] + /// + internal class Utf8JsonStreamProjectFileDependencyGroupConverter : IUtf8JsonStreamReaderConverter + { + public ProjectFileDependencyGroup Read(ref Utf8JsonStreamReader reader) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName, found " + reader.TokenType); + } + + var frameworkName = reader.GetString(); + reader.Read(); + var dependencies = reader.ReadStringArrayAsIList() ?? Array.Empty(); + + return new ProjectFileDependencyGroup(frameworkName, dependencies); + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReader.cs b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReader.cs new file mode 100644 index 00000000000..e92a2dc0c98 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReader.cs @@ -0,0 +1,326 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; + +namespace NuGet.ProjectModel +{ + /// + /// This struct is used to read over a memeory stream in parts, in order to avoid reading the entire stream into memory. + /// It functions as a wrapper around , while maintaining a stream and a buffer to read from. + /// + internal ref struct Utf8JsonStreamReader + { + private static readonly char[] DelimitedStringDelimiters = [' ', ',']; + private static readonly byte[] Utf8Bom = [0xEF, 0xBB, 0xBF]; + private static readonly JsonReaderOptions DefaultJsonReaderOptions = new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip, + }; + + private const int BufferSizeDefault = 16 * 1024; + private const int MinBufferSize = 1024; + private Utf8JsonReader _reader; +#pragma warning disable CA2213 // Disposable fields should be disposed + private Stream _stream; +#pragma warning restore CA2213 // Disposable fields should be disposed + // The buffer is used to read from the stream in chunks. + private byte[] _buffer; + private bool _disposed; + private ArrayPool _bufferPool; + private int _bufferUsed = 0; + + internal Utf8JsonStreamReader(Stream stream, int bufferSize = BufferSizeDefault, ArrayPool arrayPool = null) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (bufferSize < MinBufferSize) + { + throw new ArgumentException($"Buffer size must be at least {MinBufferSize} bytes", nameof(bufferSize)); + } + + _bufferPool = arrayPool ?? ArrayPool.Shared; + _buffer = _bufferPool.Rent(bufferSize); + _disposed = false; + _stream = stream; + _stream.Read(_buffer, 0, 3); + if (!Utf8Bom.AsSpan().SequenceEqual(_buffer.AsSpan(0, 3))) + { + _bufferUsed = 3; + } + + var initialJsonReaderState = new JsonReaderState(DefaultJsonReaderOptions); + + ReadStreamIntoBuffer(initialJsonReaderState); + _reader.Read(); + } + + internal bool IsFinalBlock => _reader.IsFinalBlock; + + internal JsonTokenType TokenType => _reader.TokenType; + + internal bool ValueTextEquals(ReadOnlySpan utf8Text) => _reader.ValueTextEquals(utf8Text); + + internal bool TryGetInt32(out int value) => _reader.TryGetInt32(out value); + + internal string GetString() => _reader.GetString(); + + internal bool GetBoolean() => _reader.GetBoolean(); + + internal int GetInt32() => _reader.GetInt32(); + + internal bool Read() + { + ThrowExceptionIfDisposed(); + + bool wasRead; + while (!(wasRead = _reader.Read()) && !_reader.IsFinalBlock) + { + GetMoreBytesFromStream(); + } + return wasRead; + } + + internal void Skip() + { + ThrowExceptionIfDisposed(); + + bool wasSkipped; + while (!(wasSkipped = _reader.TrySkip()) && !_reader.IsFinalBlock) + { + GetMoreBytesFromStream(); + } + if (!wasSkipped) + { + _reader.Skip(); + } + } + + internal IList ReadObjectAsList(IUtf8JsonStreamReaderConverter streamReaderConverter) + { + if (TokenType == JsonTokenType.Null) + { + return Array.Empty(); + } + + if (TokenType != JsonTokenType.StartObject) + { + throw new JsonException($"Expected start object token but instead found '{TokenType}'"); + } + //We use JsonObjects for the arrays so we advance to the first property in the object which is the name/ver of the first library + Read(); + + if (TokenType == JsonTokenType.EndObject) + { + return Array.Empty(); + } + + var listObjects = new List(); + do + { + listObjects.Add(streamReaderConverter.Read(ref this)); + //At this point we're looking at the EndObject token for the object, need to advance. + Read(); + } + while (TokenType != JsonTokenType.EndObject); + return listObjects; + } + + internal IList ReadListOfObjects(IUtf8JsonStreamReaderConverter streamReaderConverter) + { + if (TokenType != JsonTokenType.StartArray) + { + throw new JsonException($"Expected start array token but instead found '{TokenType}'"); + } + + IList objectList = null; + if (TokenType == JsonTokenType.StartArray) + { + while (Read() && TokenType != JsonTokenType.EndArray) + { + var convertedObject = streamReaderConverter.Read(ref this); + if (convertedObject != null) + { + objectList ??= new List(); + objectList.Add(convertedObject); + } + } + } + return objectList ?? Array.Empty(); + } + + internal string ReadNextTokenAsString() + { + ThrowExceptionIfDisposed(); + + if (Read()) + { + return _reader.ReadTokenAsString(); + } + + return null; + } + + internal IList ReadStringArrayAsIList(IList strings = null) + { + if (TokenType == JsonTokenType.StartArray) + { + while (Read() && TokenType != JsonTokenType.EndArray) + { + string value = _reader.ReadTokenAsString(); + + strings ??= new List(); + + strings.Add(value); + } + } + return strings; + } + + internal IReadOnlyList ReadDelimitedString() + { + ThrowExceptionIfDisposed(); + + if (Read()) + { + switch (TokenType) + { + case JsonTokenType.String: + var value = GetString(); + + return value.Split(DelimitedStringDelimiters, StringSplitOptions.RemoveEmptyEntries); + + default: + throw new InvalidCastException(); + } + } + + return null; + } + + internal bool ReadNextTokenAsBoolOrFalse() + { + ThrowExceptionIfDisposed(); + + if (Read() && (TokenType == JsonTokenType.False || TokenType == JsonTokenType.True)) + { + return GetBoolean(); + } + return false; + } + + internal IReadOnlyList ReadNextStringOrArrayOfStringsAsReadOnlyList() + { + ThrowExceptionIfDisposed(); + + if (Read()) + { + switch (_reader.TokenType) + { + case JsonTokenType.String: + return new[] { (string)_reader.GetString() }; + + case JsonTokenType.StartArray: + return ReadStringArrayAsReadOnlyListFromArrayStart(); + + case JsonTokenType.StartObject: + return null; + } + } + + return null; + } + + internal IReadOnlyList ReadStringArrayAsReadOnlyListFromArrayStart() + { + ThrowExceptionIfDisposed(); + + List strings = null; + + while (Read() && _reader.TokenType != JsonTokenType.EndArray) + { + string value = _reader.ReadTokenAsString(); + + strings ??= new List(); + + strings.Add(value); + } + + return (IReadOnlyList)strings ?? Array.Empty(); + } + + // This function is called when Read() returns false and we're not already in the final block + private void GetMoreBytesFromStream() + { + if (_reader.BytesConsumed < _bufferUsed) + { + // If the number of bytes consumed by the reader is less than the amount set in the buffer then we have leftover bytes + var oldBuffer = _buffer; + ReadOnlySpan leftover = oldBuffer.AsSpan((int)_reader.BytesConsumed); + _bufferUsed = leftover.Length; + + // If the leftover bytes are the same as the buffer size then we are at capacity and need to double the buffer size + if (leftover.Length == _buffer.Length) + { + _buffer = _bufferPool.Rent(_buffer.Length * 2); + leftover.CopyTo(_buffer); + _bufferPool.Return(oldBuffer, true); + } + else + { + leftover.CopyTo(_buffer); + } + } + else + { + _bufferUsed = 0; + } + + ReadStreamIntoBuffer(_reader.CurrentState); + } + + /// + /// Loops through the stream and reads it into the buffer until the buffer is full or the stream is empty, creates the Utf8JsonReader. + /// + private void ReadStreamIntoBuffer(JsonReaderState jsonReaderState) + { + int bytesRead; + do + { + var spaceLeftInBuffer = _buffer.Length - _bufferUsed; + bytesRead = _stream.Read(_buffer, _bufferUsed, spaceLeftInBuffer); + _bufferUsed += bytesRead; + } + while (bytesRead != 0 && _bufferUsed != _buffer.Length); + _reader = new Utf8JsonReader(_buffer.AsSpan(0, _bufferUsed), isFinalBlock: bytesRead == 0, jsonReaderState); + } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + byte[] toReturn = _buffer; + _buffer = null!; + _bufferPool.Return(toReturn, true); + } + } + + private void ThrowExceptionIfDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(Utf8JsonStreamReader)); + } + } + } +} diff --git a/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReaderConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReaderConverter.cs new file mode 100644 index 00000000000..730560501c7 --- /dev/null +++ b/src/NuGet.Core/NuGet.ProjectModel/Utf8JsonStreamReaderConverter.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +namespace NuGet.ProjectModel +{ + /// + /// An abstract class that defines a function for reading a into a + /// + /// + internal interface IUtf8JsonStreamReaderConverter + { + T Read(ref Utf8JsonStreamReader reader); + } +} diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NetworkCallCountTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NetworkCallCountTest.cs index eface8291ce..c28b7f8fd9d 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NetworkCallCountTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NetworkCallCountTest.cs @@ -1553,23 +1553,23 @@ private void CreateMixedConfigAndJson(string workingPath) Util.CreateFile(proj3Dir, "project.json", @"{ - 'dependencies': { - 'packageD': '1.0.0', - 'packageE': '1.0.*' + ""dependencies"": { + ""packageD"": ""1.0.0"", + ""packageE"": ""1.0.*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); Util.CreateFile(proj4Dir, "project.json", @"{ - 'dependencies': { - 'packageE': '1.0.0', - 'packageF': '*' + ""dependencies"": { + ""packageE"": ""1.0.0"", + ""packageF"": ""*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetRestoreCommandTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetRestoreCommandTest.cs index 571e6fd5b39..8fd0249e601 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetRestoreCommandTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetRestoreCommandTest.cs @@ -1288,12 +1288,12 @@ public void RestoreCommand_FromProjectJson_RelativeGlobalPackagesFolder() var projectJson = @"{ - 'dependencies': { - 'packageA': '1.1.0', - 'packageB': '2.2.0' + ""dependencies"": { + ""packageA"": ""1.1.0"", + ""packageB"": ""2.2.0"" }, - 'frameworks': { - 'netcore50': { } + ""frameworks"": { + ""netcore50"": { } } }"; @@ -1992,12 +1992,12 @@ public void RestoreCommand_FromSolutionFile_ProjectsInParentDir() Util.CreateFile(Path.Combine(basePath, "A", "A.Util"), "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0', - 'packageB': '2.2.0' + ""dependencies"": { + ""packageA"": ""1.1.0"", + ""packageB"": ""2.2.0"" }, - 'frameworks': { - 'netcore50': { } + ""frameworks"": { + ""netcore50"": { } } }"); Util.CreateFile(Path.Combine(basePath, "B"), "B.csproj", @@ -2022,10 +2022,10 @@ public void RestoreCommand_FromSolutionFile_ProjectsInParentDir() Util.CreateFile(Path.Combine(basePath, "B"), "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'netcore50': { } + ""frameworks"": { + ""netcore50"": { } } }"); diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreProjectJsonTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreProjectJsonTest.cs index 4702b9f82f4..c766955223d 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreProjectJsonTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreProjectJsonTest.cs @@ -41,11 +41,11 @@ public async Task RestoreProjectJson_MinClientVersionFailAsync() await SimpleTestPackageUtility.CreatePackagesAsync(repositoryPath, packageContext); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0' + ""dependencies"": { + ""packageA"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -90,20 +90,20 @@ public void RestoreProjectJson_RestoreFolder_VerifyFailure() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { + ""version"": ""1.0.0-*"", + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -151,10 +151,10 @@ public void RestoreProjectJson_RestoreForSingleProject() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -163,11 +163,11 @@ public void RestoreProjectJson_RestoreForSingleProject() Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { + ""version"": ""1.0.0-*"", + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -267,10 +267,10 @@ public async Task RestoreProjectJson_RestoreWithFallbackFolderAsync() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -279,13 +279,13 @@ public async Task RestoreProjectJson_RestoreWithFallbackFolderAsync() Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { - 'packageA': '1.0.0', - 'packageB': '1.0.0' + ""version"": ""1.0.0-*"", + ""dependencies"": { + ""packageA"": ""1.0.0"", + ""packageB"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -332,10 +332,10 @@ public void RestoreProjectJson_RestoreFromSlnWithCsproj() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -412,26 +412,26 @@ public void RestoreProjectJson_RestoreFromSlnWithCsproj_InconsitentCaseForProjec Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'net45': { } + ""frameworks"": { + ""net45"": { } } }"); Util.CreateFile(projectDir2, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'net45': { } + ""frameworks"": { + ""net45"": { } } }"); Util.CreateFile(projectDir3, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'net45': { } + ""frameworks"": { + ""net45"": { } } }"); @@ -570,10 +570,10 @@ public void RestoreProjectJson_P2PTimeouts(string timeout, int projectCount, int Util.CreateFile(projectDir, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -687,10 +687,10 @@ public async Task RestoreProjectJson_RestoreFromSlnWithReferenceOutputAssemblyFa Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -713,12 +713,12 @@ public async Task RestoreProjectJson_RestoreFromSlnWithReferenceOutputAssemblyFa Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { + ""version"": ""1.0.0-*"", + ""dependencies"": { ""packageA"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -897,10 +897,10 @@ public void RestoreProjectJson_RestoreCSProj() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -947,10 +947,10 @@ public void RestoreProjectJson_RestoreUnknownProj() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { + ""dependencies"": { }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1002,11 +1002,11 @@ public async Task RestoreProjectJson_RestoreFromSlnWithUnknownProjAndCsproj() Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1014,12 +1014,12 @@ public async Task RestoreProjectJson_RestoreFromSlnWithUnknownProjAndCsproj() Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""version"": ""1.0.0-*"", + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1112,11 +1112,11 @@ public async Task RestoreProjectJson_RestoreFromSlnUsesNuGetFolderSettingsAsync( Util.CreateFile(projectDir1, "project.json", @"{ - 'dependencies': { - 'packageA': '1.0.0' + ""dependencies"": { + ""packageA"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1124,12 +1124,12 @@ public async Task RestoreProjectJson_RestoreFromSlnUsesNuGetFolderSettingsAsync( Util.CreateFile(projectDir2, "project.json", @"{ - 'version': '1.0.0-*', - 'dependencies': { - 'packageB': '1.0.0' + ""version"": ""1.0.0-*"", + ""dependencies"": { + ""packageB"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1215,11 +1215,11 @@ public void RestoreProjectJson_FloatReleaseLabelHighestPrelease() Util.CreateTestPackage("packageA", "1.0.0-beta-01", repositoryPath); Util.CreateTestPackage("packageA", "1.0.0-beta-02", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0-*' + ""dependencies"": { + ""packageA"": ""1.0.0-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1271,11 +1271,11 @@ public void RestoreProjectJson_FloatReleaseLabelTakesStable() Util.CreateTestPackage("packageA", "1.0.0-beta-01", repositoryPath); Util.CreateTestPackage("packageA", "1.0.0-beta-02", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0-*' + ""dependencies"": { + ""packageA"": ""1.0.0-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1383,11 +1383,11 @@ public void RestoreProjectJson_RestoreFiltersToStablePackages() Util.CreateTestPackage("packageB", "2.0.0-beta", repositoryPath); Util.CreateTestPackage("packageB", "3.0.0", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0' + ""dependencies"": { + ""packageA"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1439,12 +1439,12 @@ public void RestoreProjectJson_RestoreBumpsFromStableToPrereleaseWhenNeeded() Util.CreateTestPackage("packageC", "1.0.0", repositoryPath); Util.CreateTestPackage("packageC", "2.0.0-beta", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0', - 'packageB': '1.0.0-*' + ""dependencies"": { + ""packageA"": ""1.0.0"", + ""packageB"": ""1.0.0-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1495,12 +1495,12 @@ public void RestoreProjectJson_RestoreDowngradesStableDependency() Util.CreateTestPackage("packageC", "3.0.0", repositoryPath); Util.CreateTestPackage("packageC", "2.1.0", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0', - 'packageB': '1.0.0' + ""dependencies"": { + ""packageA"": ""1.0.0"", + ""packageB"": ""1.0.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1551,12 +1551,12 @@ public void RestoreProjectJson_RestoreDowngradesFromStableToPrereleaseWhenNeeded Util.CreateTestPackage("packageC", "2.0.0-beta", repositoryPath); Util.CreateConfigForGlobalPackagesFolder(workingPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.0.0', - 'packageB': '1.0.0-*' + ""dependencies"": { + ""packageA"": ""1.0.0"", + ""packageB"": ""1.0.0-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; @@ -1613,21 +1613,21 @@ public async Task RestoreProjectJson_SolutionFileWithAllProjectsInOneFolder() Util.CreateFile(projectDir, "testA.project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); Util.CreateFile(projectDir, "testB.project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1724,11 +1724,11 @@ public async Task RestoreProjectJson_GenerateFilesWithProjectNameFromCSProj() Util.CreateFile(workingPath, "test.project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1785,11 +1785,11 @@ public async Task RestoreProjectJson_GenerateTargetsFileFromSln() Util.CreateFile(projectDir, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1876,12 +1876,12 @@ public async Task RestoreProjectJson_GenerateTargetsFileFromCSProj() Util.CreateFile(workingPath, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*', - 'packageB': '2.2.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"", + ""packageB"": ""2.2.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -1972,12 +1972,12 @@ public async Task RestoreProjectJson_GenerateTargetsForFallbackFolderAsync() Util.CreateFile(projectDir, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*', - 'packageB': '2.2.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"", + ""packageB"": ""2.2.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -2038,12 +2038,12 @@ public async Task RestoreProjectJson_GenerateTargetsFileFromNuProj() Util.CreateFile(workingPath, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*', - 'packageB': '2.2.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"", + ""packageB"": ""2.2.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -2103,12 +2103,12 @@ public async Task RestoreProjectJson_GenerateTargetsFileWithFolder() Util.CreateFile(workingPath, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*', - 'packageB': '2.2.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"", + ""packageB"": ""2.2.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -2165,11 +2165,11 @@ public async Task RestoreProjectJson_GenerateTargetsForRootBuildFolderIgnoreSubF Util.CreateFile(workingPath, "project.json", @"{ - 'dependencies': { - 'packageA': '3.1.0', + ""dependencies"": { + ""packageA"": ""3.1.0"", }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -2232,12 +2232,12 @@ public async Task RestoreProjectJson_GenerateTargetsPersistsWithMultipleRestores Util.CreateFile(workingPath, "project.json", @"{ - 'dependencies': { - 'packageA': '1.1.0-beta-*', - 'packageB': '2.2.0-beta-*' + ""dependencies"": { + ""packageA"": ""1.1.0-beta-*"", + ""packageB"": ""2.2.0-beta-*"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"); @@ -2322,12 +2322,12 @@ public void RestoreProjectJson_CorruptedLockFile() Util.CreateTestPackage("packageA", "1.1.0", repositoryPath); Util.CreateTestPackage("packageB", "2.2.0", repositoryPath); var projectJson = @"{ - 'dependencies': { - 'packageA': '1.1.0', - 'packageB': '2.2.0' + ""dependencies"": { + ""packageA"": ""1.1.0"", + ""packageB"": ""2.2.0"" }, - 'frameworks': { - 'uap10.0': { } + ""frameworks"": { + ""uap10.0"": { } } }"; diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs index 042899e97be..3b2060f8abb 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs @@ -994,14 +994,14 @@ public static void CreateConfigFile(string path, string configFileName, string t public static string GetProjectJsonFileContents(string targetFramework, IEnumerable packages) { - var dependencies = string.Join(", ", packages.Select(package => $"'{package.Id}': '{package.Version}'")); + var dependencies = string.Join(", ", packages.Select(package => $"\"{package.Id}\": \"{package.Version}\"")); return $@" {{ - 'dependencies': {{ + ""dependencies"": {{ {dependencies} }}, - 'frameworks': {{ - '{targetFramework}': {{ }} + ""frameworks"": {{ + ""{targetFramework}"": {{ }} }} }}"; } diff --git a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/BuildIntegration/BuildIntegrationTestUtility.cs b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/BuildIntegration/BuildIntegrationTestUtility.cs index 6e67ad8b44a..8547cdf1b75 100644 --- a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/BuildIntegration/BuildIntegrationTestUtility.cs +++ b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/BuildIntegration/BuildIntegrationTestUtility.cs @@ -37,12 +37,12 @@ public static JObject BasicConfig } public const string ProjectJsonWithPackage = @"{ - 'dependencies': { - 'EntityFramework': '5.0.0' + ""dependencies"": { + ""EntityFramework"": ""5.0.0"" }, - 'frameworks': { - 'net46': { } - } + ""frameworks"": { + ""net46"": { } + } }"; public static ExternalProjectReference CreateReference(string name) diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/DependencyTargetTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/DependencyTargetTests.cs index b86dcd11bba..0fe32011470 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/DependencyTargetTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/DependencyTargetTests.cs @@ -1,7 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.IO; using System.Linq; +using System.Text; +using NuGet.Common; using NuGet.LibraryModel; using Xunit; @@ -9,8 +12,9 @@ namespace NuGet.ProjectModel.Test { public class DependencyTargetTests { - [Fact] - public void DependencyTarget_ExternalProjectValue() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_ExternalProjectValue(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -26,15 +30,16 @@ public void DependencyTarget_ExternalProjectValue() }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); // Assert Assert.Equal(LibraryDependencyTarget.ExternalProject, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void DependencyTarget_ProjectValue() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_ProjectValue(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -50,15 +55,16 @@ public void DependencyTarget_ProjectValue() }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); // Assert Assert.Equal(LibraryDependencyTarget.Project, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void DependencyTarget_PackageValue() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_PackageValue(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -74,15 +80,16 @@ public void DependencyTarget_PackageValue() }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); // Assert Assert.Equal(LibraryDependencyTarget.Package, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void DependencyTarget_CaseInsensitive() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_CaseInsensitive(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -98,15 +105,16 @@ public void DependencyTarget_CaseInsensitive() }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); // Assert Assert.Equal(LibraryDependencyTarget.Package, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void DependencyTarget_DefaultValueDefault() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_DefaultValueDefault(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -119,7 +127,7 @@ public void DependencyTarget_DefaultValueDefault() }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); // Assert @@ -127,8 +135,9 @@ public void DependencyTarget_DefaultValueDefault() Assert.Equal(expected, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void DependencyTarget_UnknownValueFails() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_UnknownValueFails(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -149,7 +158,7 @@ public void DependencyTarget_UnknownValueFails() try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); } catch (FileFormatException ex) @@ -161,11 +170,16 @@ public void DependencyTarget_UnknownValueFails() Assert.NotNull(exception); Assert.Equal("Invalid dependency target value 'blah'.", exception.Message); Assert.EndsWith("project.json", exception.Path); - Assert.Equal(5, exception.Line); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(5, exception.Line); + } } - [Fact] - public void DependencyTarget_NonWhiteListValueFails() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_NonWhiteListValueFails(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -186,7 +200,7 @@ public void DependencyTarget_NonWhiteListValueFails() try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); } catch (FileFormatException ex) @@ -198,11 +212,16 @@ public void DependencyTarget_NonWhiteListValueFails() Assert.NotNull(exception); Assert.Equal("Invalid dependency target value 'winmd'.", exception.Message); Assert.EndsWith("project.json", exception.Path); - Assert.Equal(5, exception.Line); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(5, exception.Line); + } } - [Fact] - public void DependencyTarget_MultipleValuesFail() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_MultipleValuesFail(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -223,7 +242,7 @@ public void DependencyTarget_MultipleValuesFail() try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); var dependency = spec.Dependencies.Single(); } catch (FileFormatException ex) @@ -235,11 +254,16 @@ public void DependencyTarget_MultipleValuesFail() Assert.NotNull(exception); Assert.Equal("Invalid dependency target value 'package,project'.", exception.Message); Assert.EndsWith("project.json", exception.Path); - Assert.Equal(5, exception.Line); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(5, exception.Line); + } } - [Fact] - public void DependencyTarget_AcceptsWhitespace() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void DependencyTarget_AcceptsWhitespace(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -256,11 +280,18 @@ public void DependencyTarget_AcceptsWhitespace() // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", environmentVariableReader); // Assert var dependency = spec.Dependencies.Single(); Assert.Equal(LibraryDependencyTarget.Package, dependency.LibraryRange.TypeConstraint); } + + private static PackageSpec GetPackageSpec(string json, string name, string packageSpecPath, IEnvironmentVariableReader environmentVariableReader) + { + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + return JsonPackageSpecReader.GetPackageSpec(stream, name, packageSpecPath, null, environmentVariableReader, true); + } + } } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs index 081729f7e29..5b127fa7792 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs @@ -17,14 +17,17 @@ using NuGet.Versioning; using Test.Utility; using Xunit; +using System.Text.Json; namespace NuGet.ProjectModel.Test { [UseCulture("")] // Fix tests failing on systems with non-English locales + [Obsolete] public class JsonPackageSpecReaderTests { - [Fact] - public void PackageSpecReader_PackageMissingVersion() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackageMissingVersion(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ @@ -43,7 +46,7 @@ public void PackageSpecReader_PackageMissingVersion() try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); } catch (Exception ex) { @@ -54,50 +57,53 @@ public void PackageSpecReader_PackageMissingVersion() Assert.Contains("specify a version range", exception.Message); } - [Fact] - public void PackageSpecReader_ProjectMissingVersion() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ProjectMissingVersion(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""project"" - } - }, - ""frameworks"": { - ""net46"": {} - } - }"; + ""dependencies"": { + ""packageA"": { + ""target"": ""project"" + } + }, + ""frameworks"": { + ""net46"": {} + } + }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); var range = spec.Dependencies.Single().LibraryRange.VersionRange; // Assert Assert.Equal(VersionRange.All, range); } - [Fact] - public void PackageSpecReader_PackageEmptyVersion() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackageEmptyVersion(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": """" - } - }, - ""frameworks"": { - ""net46"": {} - } - }"; + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": """" + } + }, + ""frameworks"": { + ""net46"": {} + } + }"; Exception exception = null; try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); } catch (Exception ex) { @@ -108,27 +114,28 @@ public void PackageSpecReader_PackageEmptyVersion() Assert.Contains("specify a version range", exception.Message); } - [Fact] - public void PackageSpecReader_PackageWhitespaceVersion() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackageWhitespaceVersion(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": "" "" - } - }, - ""frameworks"": { - ""net46"": {} - } - }"; + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": "" "" + } + }, + ""frameworks"": { + ""net46"": {} + } + }"; Exception exception = null; try { - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); } catch (Exception ex) { @@ -139,44 +146,46 @@ public void PackageSpecReader_PackageWhitespaceVersion() Assert.Contains("not a valid version string", exception.Message); } - [Fact] - public void PackageSpecReader_FrameworkAssemblyEmptyVersion() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_FrameworkAssemblyEmptyVersion(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""frameworks"": { - ""net46"": { - ""frameworkAssemblies"": { - ""packageA"": """" + ""frameworks"": { + ""net46"": { + ""frameworkAssemblies"": { + ""packageA"": """" + } + } } - } - } - }"; + }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); var range = spec.TargetFrameworks.Single().Dependencies.Single().LibraryRange.VersionRange; // Assert Assert.Equal(VersionRange.All, range); } - [Fact] - public void PackageSpecReader_ExplicitIncludesOverrideTypePlatform() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ExplicitIncludesOverrideTypePlatform(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""redist"": { - ""version"": ""1.0.0"", - ""type"": ""platform"", - ""include"": ""analyzers"" - } - } - }"; + ""dependencies"": { + ""redist"": { + ""version"": ""1.0.0"", + ""type"": ""platform"", + ""include"": ""analyzers"" + } + } + }"; // Act - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var dep = actual.Dependencies.FirstOrDefault(d => d.Name.Equals("redist")); @@ -187,30 +196,30 @@ public void PackageSpecReader_ExplicitIncludesOverrideTypePlatform() } [Theory] - [InlineData("{}")] - [InlineData(@"{ - ""packOptions"": {} - }")] - [InlineData(@"{ - ""packOptions"": { - ""foo"": [1, 2] - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": null - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [] - } - }")] + [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": {} + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""foo"": [1, 2] + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": null + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [] + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] #pragma warning disable CS0612 // Type or member is obsolete - public void PackageSpecReader_PackOptions_Default(string json) + public void PackageSpecReader_PackOptions_Default(IEnvironmentVariableReader environmentVariableReader, string json) { // Arrange & Act - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.NotNull(actual.PackOptions); @@ -218,33 +227,51 @@ public void PackageSpecReader_PackOptions_Default(string json) Assert.Empty(actual.PackOptions.PackageType); } + [Theory] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": ""foo"" - } - }", new[] { "foo" })] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": ""foo, bar"" - } - }", new[] { "foo, bar" })] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ ""foo"" ] - } - }", new[] { "foo" })] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ ""foo, bar"" ] - } - }", new[] { "foo, bar" })] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ ""foo"", ""bar"" ] - } - }", new[] { "foo", "bar" })] - public void PackageSpecReader_PackOptions_ValidPackageType(string json, string[] expectedNames) + [MemberData(nameof(TestEnvironmentVariableReader), @" + ""packOptions"": { + ""packageType"": ""foo"" + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_Malformed_Default(IEnvironmentVariableReader environmentVariableReader, string json) + { + // Arrange & Act + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); + + // Assert + Assert.NotNull(actual.PackOptions); + Assert.NotNull(actual.PackOptions.PackageType); + Assert.Empty(actual.PackOptions.PackageType); + } + + [Theory] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": ""foo"" + } + }", new[] { "foo" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": ""foo, bar"" + } + }", new[] { "foo, bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ ""foo"" ] + } + }", new[] { "foo" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ ""foo, bar"" ] + } + }", new[] { "foo, bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ ""foo"", ""bar"" ] + } + }", new[] { "foo", "bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackOptions_ValidPackageType(IEnvironmentVariableReader environmentVariableReader, string json, string[] expectedNames) { // Arrange var expected = expectedNames @@ -252,7 +279,7 @@ public void PackageSpecReader_PackOptions_ValidPackageType(string json, string[] .ToArray(); // Act - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.NotNull(actual.PackOptions); @@ -260,85 +287,87 @@ public void PackageSpecReader_PackOptions_ValidPackageType(string json, string[] Assert.Equal(expected, actual.PackOptions.PackageType.ToArray()); } + [Theory] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": 1 - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": false - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": 1.0 - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": {} - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": { - ""name"": ""foo"" - } - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ - { ""name"": ""foo"" }, - { ""name"": ""bar"" } - ] - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ - ""foo"", - null - ] - } - }")] - [InlineData(@"{ - ""packOptions"": { - ""packageType"": [ - ""foo"", - true - ] - } - }")] - public void PackageSpecReader_PackOptions_InvalidPackageType(string json) + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": 1 + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": false + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": 1.0 + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": {} + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": { + ""name"": ""foo"" + } + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ + { ""name"": ""foo"" }, + { ""name"": ""bar"" } + ] + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ + ""foo"", + null + ] + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""packOptions"": { + ""packageType"": [ + ""foo"", + true + ] + } + }", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackOptions_InvalidPackageType(IEnvironmentVariableReader environmentVariableReader, string json) { // Arrange & Act & Assert var actual = Assert.Throws( - () => JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json")); + () => GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader)); Assert.Contains("The pack options package type must be a string or array of strings in 'project.json'.", actual.Message); } - [Fact] - public void PackageSpecReader_PackOptions_Files1() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackOptions_Files1(IEnvironmentVariableReader environmentVariableReader) { // Arrange & Act var json = @"{ - ""packOptions"": { - ""files"": { - ""include"": ""file1"", - ""exclude"": ""file2"", - ""includeFiles"": ""file3"", - ""excludeFiles"": ""file4"", - ""mappings"": { - ""dest/path"": ""./src/path"" - } - } - } - }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + ""packOptions"": { + ""files"": { + ""include"": ""file1"", + ""exclude"": ""file2"", + ""includeFiles"": ""file3"", + ""excludeFiles"": ""file4"", + ""mappings"": { + ""dest/path"": ""./src/path"" + } + } + } + }"; + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.NotNull(actual.PackOptions); @@ -360,27 +389,28 @@ public void PackageSpecReader_PackOptions_Files1() Assert.Equal("./src/path", actual.PackOptions.Mappings.First().Value.Include.First()); } - [Fact] - public void PackageSpecReader_PackOptions_Files2() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_PackOptions_Files2(IEnvironmentVariableReader environmentVariableReader) { // Arrange & Act var json = @"{ - ""packOptions"": { - ""files"": { - ""include"": [""file1a"", ""file1b""], - ""exclude"": [""file2a"", ""file2b""], - ""includeFiles"": [""file3a"", ""file3b""], - ""excludeFiles"": [""file4a"", ""file4b""], - ""mappings"": { - ""dest/path1"": [""./src/path1"", ""./src/path2""], - ""dest/path2"": { - ""includeFiles"": [""map1a"", ""map1b""], - }, - } - } - } - }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + ""packOptions"": { + ""files"": { + ""include"": [""file1a"", ""file1b""], + ""exclude"": [""file2a"", ""file2b""], + ""includeFiles"": [""file3a"", ""file3b""], + ""excludeFiles"": [""file4a"", ""file4b""], + ""mappings"": { + ""dest/path1"": [""./src/path1"", ""./src/path2""], + ""dest/path2"": { + ""includeFiles"": [""map1a"", ""map1b""], + }, + } + } + } + }"; + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.NotNull(actual.PackOptions); @@ -414,30 +444,30 @@ public void PackageSpecReader_PackOptions_Files2() } [Theory] - [InlineData("{}", null, true)] - [InlineData(@"{ - ""buildOptions"": {} - }", null, false)] - [InlineData(@"{ - ""buildOptions"": { - ""outputName"": ""dllName"" - } - }", "dllName", false)] - [InlineData(@"{ - ""buildOptions"": { - ""outputName"": ""dllName2"", - ""emitEntryPoint"": true - } - }", "dllName2", false)] - [InlineData(@"{ - ""buildOptions"": { - ""outputName"": null - } - }", null, false)] - public void PackageSpecReader_BuildOptions(string json, string expectedValue, bool nullBuildOptions) + [MemberData(nameof(TestEnvironmentVariableReader), "{}", null, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""buildOptions"": {} + }", null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""buildOptions"": { + ""outputName"": ""dllName"" + } + }", "dllName", false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""buildOptions"": { + ""outputName"": ""dllName2"", + ""emitEntryPoint"": true + } + }", "dllName2", false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), @"{ + ""buildOptions"": { + ""outputName"": null + } + }", null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_BuildOptions(IEnvironmentVariableReader environmentVariableReader, string json, string expectedValue, bool nullBuildOptions) { // Arrange & Act - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert if (nullBuildOptions) @@ -452,23 +482,24 @@ public void PackageSpecReader_BuildOptions(string json, string expectedValue, bo } #pragma warning restore CS0612 // Type or member is obsolete - [Fact] - public void PackageSpecReader_ReadsWithoutRestoreSettings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsWithoutRestoreSettings(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": ""1.0.0"" - } - }, - ""frameworks"": { - ""net46"": {} - }, - }"; + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": ""1.0.0"" + } + }, + ""frameworks"": { + ""net46"": {} + }, + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.NotNull(actual); @@ -476,27 +507,28 @@ public void PackageSpecReader_ReadsWithoutRestoreSettings() Assert.False(actual.RestoreSettings.HideWarningsAndErrors); } - [Fact] - public void PackageSpecReader_ReadsDependencyWithMultipleNoWarn() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsDependencyWithMultipleNoWarn(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": ""1.0.0"", - ""noWarn"": [ - ""NU1500"", - ""NU1107"" - ] - } - }, - ""frameworks"": { - ""net46"": {} - }, - }"; - - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": ""1.0.0"", + ""noWarn"": [ + ""NU1500"", + ""NU1107"" + ] + } + }, + ""frameworks"": { + ""net46"": {} + }, + }"; + + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var dep = actual.Dependencies.FirstOrDefault(d => d.Name.Equals("packageA")); @@ -507,26 +539,27 @@ public void PackageSpecReader_ReadsDependencyWithMultipleNoWarn() Assert.True(dep.NoWarn.Contains(NuGetLogCode.NU1107)); } - [Fact] - public void PackageSpecReader_ReadsDependencyWithSingleNoWarn() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsDependencyWithSingleNoWarn(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": ""1.0.0"", - ""noWarn"": [ - ""NU1500"" - ] - } - }, - ""frameworks"": { - ""net46"": {} - }, - }"; - - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": ""1.0.0"", + ""noWarn"": [ + ""NU1500"" + ] + } + }, + ""frameworks"": { + ""net46"": {} + }, + }"; + + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var dep = actual.Dependencies.FirstOrDefault(d => d.Name.Equals("packageA")); @@ -536,25 +569,26 @@ public void PackageSpecReader_ReadsDependencyWithSingleNoWarn() Assert.True(dep.NoWarn.Contains(NuGetLogCode.NU1500)); } - [Fact] - public void PackageSpecReader_ReadsDependencyWithSingleEmptyNoWarn() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsDependencyWithSingleEmptyNoWarn(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": ""1.0.0"", - ""noWarn"": [ - ] - } - }, - ""frameworks"": { - ""net46"": {} - }, - }"; - - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": ""1.0.0"", + ""noWarn"": [ + ] + } + }, + ""frameworks"": { + ""net46"": {} + }, + }"; + + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var dep = actual.Dependencies.FirstOrDefault(d => d.Name.Equals("packageA")); @@ -563,61 +597,62 @@ public void PackageSpecReader_ReadsDependencyWithSingleEmptyNoWarn() Assert.Equal(dep.NoWarn.Count, 0); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithWarningProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithWarningProperties(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - }, - ""warningProperties"": { - ""allWarningsAsErrors"": true, - ""noWarn"": [ - ""NU1601"", - ], - ""warnAsError"": [ - ""NU1500"", - ""NU1501"" - ], - ""warnNotAsError"": [ - ""NU1801"", - ""NU1802"" - ] - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + }, + ""warningProperties"": { + ""allWarningsAsErrors"": true, + ""noWarn"": [ + ""NU1601"", + ], + ""warnAsError"": [ + ""NU1500"", + ""NU1501"" + ], + ""warnNotAsError"": [ + ""NU1801"", + ""NU1802"" + ] + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -636,54 +671,55 @@ public void PackageSpecReader_ReadsRestoreMetadataWithWarningProperties() Assert.True(warningProperties.WarningsNotAsErrors.Contains(NuGetLogCode.NU1802)); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_NoWarn() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_NoWarn(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - }, - ""warningProperties"": { - ""allWarningsAsErrors"": true, - ""warnAsError"": [ - ""NU1500"", - ""NU1501"" - ] - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + }, + ""warningProperties"": { + ""allWarningsAsErrors"": true, + ""warnAsError"": [ + ""NU1500"", + ""NU1501"" + ] + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -698,53 +734,54 @@ public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_NoW Assert.True(warningProperties.WarningsAsErrors.Contains(NuGetLogCode.NU1501)); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_WarnAsError() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_WarnAsError(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - }, - ""warningProperties"": { - ""allWarningsAsErrors"": true, - ""noWarn"": [ - ""NU1601"", - ] - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + }, + ""warningProperties"": { + ""allWarningsAsErrors"": true, + ""noWarn"": [ + ""NU1601"", + ] + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -758,56 +795,57 @@ public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_War Assert.Equal(0, warningProperties.WarningsAsErrors.Count); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_AllWarningsAsErrors() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_AllWarningsAsErrors(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - }, - ""warningProperties"": { - ""noWarn"": [ - ""NU1601"", - ], - ""warnAsError"": [ - ""NU1500"", - ""NU1501"" - ] - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + }, + ""warningProperties"": { + ""noWarn"": [ + ""NU1601"", + ], + ""warnAsError"": [ + ""NU1500"", + ""NU1501"" + ] + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -823,49 +861,50 @@ public void PackageSpecReader_ReadsRestoreMetadataWithWarningPropertiesAndNo_All Assert.True(warningProperties.WarningsAsErrors.Contains(NuGetLogCode.NU1501)); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithEmptyWarningPropertiesAnd() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithEmptyWarningPropertiesAnd(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - }, - ""warningProperties"": { - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + }, + ""warningProperties"": { + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -878,47 +917,48 @@ public void PackageSpecReader_ReadsRestoreMetadataWithEmptyWarningPropertiesAnd( Assert.Equal(0, warningProperties.WarningsAsErrors.Count); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithNoWarningProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithNoWarningProperties(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""configFilePaths"": [ - ""b"", - ""a"", - ""c"" - ], - ""fallbackFolders"": [ - ""b"", - ""a"", - ""c"" - ], - ""originalTargetFrameworks"": [ - ""b"", - ""a"", - ""c"" - ], - ""sources"": { - ""source"": {} - }, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""projectReferences"": {} - } - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""configFilePaths"": [ + ""b"", + ""a"", + ""c"" + ], + ""fallbackFolders"": [ + ""b"", + ""a"", + ""c"" + ], + ""originalTargetFrameworks"": [ + ""b"", + ""a"", + ""c"" + ], + ""sources"": { + ""source"": {} + }, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""projectReferences"": {} + } + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -928,264 +968,285 @@ public void PackageSpecReader_ReadsRestoreMetadataWithNoWarningProperties() Assert.NotNull(warningProperties); } - [Fact] - public void PackageSpecReader_RuntimeIdentifierPathNullIfEmpty() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_RuntimeIdentifierPathNullIfEmpty(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""frameworks"": { - ""net46"": { - ""dependencies"": { - ""packageA"": { - ""target"": ""package"", - ""version"": ""1.0.0"", - ""noWarn"": [ - ""NU1500"" - ] - } - } - } - } - }"; + ""frameworks"": { + ""net46"": { + ""dependencies"": { + ""packageA"": { + ""target"": ""package"", + ""version"": ""1.0.0"", + ""noWarn"": [ + ""NU1500"" + ] + } + } + } + } + }"; // Act - var spec = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var spec = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert Assert.Null(spec.TargetFrameworks.First().RuntimeIdentifierGraphPath); } #pragma warning disable CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenAuthorsPropertyIsAbsent_ReturnsEmptyAuthors() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsPropertyIsAbsent_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Empty(packageSpec.Authors); } - [Fact] - public void GetPackageSpec_WhenAuthorsValueIsNull_ReturnsEmptyAuthors() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsValueIsNull_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"authors\":null}"); + PackageSpec packageSpec = GetPackageSpec("{\"authors\":null}", environmentVariableReader); Assert.Empty(packageSpec.Authors); } - [Fact] - public void GetPackageSpec_WhenAuthorsValueIsString_ReturnsEmptyAuthors() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsValueIsString_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"authors\":\"b\"}"); + PackageSpec packageSpec = GetPackageSpec("{\"authors\":\"b\"}", environmentVariableReader); Assert.Empty(packageSpec.Authors); } [Theory] - [InlineData("")] - [InlineData("/**/")] - public void GetPackageSpec_WhenAuthorsValueIsEmptyArray_ReturnsEmptyAuthors(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "/**/", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsValueIsEmptyArray_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader, string value) { - PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}", environmentVariableReader); Assert.Empty(packageSpec.Authors); } [Theory] - [InlineData("{}")] - [InlineData("[]")] - public void GetPackageSpec_WhenAuthorsValueElementIsNotConvertibleToString_Throws(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[]", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsValueElementIsNotConvertibleToString_Throws(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"authors\":[{value}]}}"; - Assert.Throws(() => GetPackageSpec(json)); + Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("true", "True")] - [InlineData("-2", "-2")] - [InlineData("3.14", "3.14")] - public void GetPackageSpec_WhenAuthorsValueElementIsConvertibleToString_ReturnsAuthor(string value, string expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenAuthorsValueElementIsConvertibleToString_ReturnsAuthor(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { - PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}", environmentVariableReader); Assert.Collection(packageSpec.Authors, author => Assert.Equal(expectedValue, author)); } - [Fact] - public void GetPackageSpec_WhenBuildOptionsPropertyIsAbsent_ReturnsNullBuildOptions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenBuildOptionsPropertyIsAbsent_ReturnsNullBuildOptions(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Null(packageSpec.BuildOptions); } - [Fact] - public void GetPackageSpec_WhenBuildOptionsValueIsEmptyObject_ReturnsBuildOptions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenBuildOptionsValueIsEmptyObject_ReturnsBuildOptions(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{}}"); + PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{}}", environmentVariableReader); Assert.NotNull(packageSpec.BuildOptions); Assert.Null(packageSpec.BuildOptions.OutputName); } - [Fact] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsNull_ReturnsNullOutputName() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsNull_ReturnsNullOutputName(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{\"outputName\":null}}"); + PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{\"outputName\":null}}", environmentVariableReader); Assert.Null(packageSpec.BuildOptions.OutputName); } - [Fact] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsValid_ReturnsOutputName() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsValid_ReturnsOutputName(IEnvironmentVariableReader environmentVariableReader) { const string expectedResult = "a"; var json = $"{{\"buildOptions\":{{\"outputName\":\"{expectedResult}\"}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.BuildOptions.OutputName); } [Theory] - [InlineData("-2", "-2")] - [InlineData("3.14", "3.14")] - [InlineData("true", "True")] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsConvertibleToString_ReturnsOutputName(string outputName, string expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsConvertibleToString_ReturnsOutputName(IEnvironmentVariableReader environmentVariableReader, string outputName, string expectedValue) { - PackageSpec packageSpec = GetPackageSpec($"{{\"buildOptions\":{{\"outputName\":{outputName}}}}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"buildOptions\":{{\"outputName\":{outputName}}}}}", environmentVariableReader); Assert.Equal(expectedValue, packageSpec.BuildOptions.OutputName); } - [Fact] - public void GetPackageSpec_WhenContentFilesPropertyIsAbsent_ReturnsEmptyContentFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesPropertyIsAbsent_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Empty(packageSpec.ContentFiles); } - [Fact] - public void GetPackageSpec_WhenContentFilesValueIsNull_ReturnsEmptyContentFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesValueIsNull_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":null}"); + PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":null}", environmentVariableReader); Assert.Empty(packageSpec.ContentFiles); } - [Fact] - public void GetPackageSpec_WhenContentFilesValueIsString_ReturnsEmptyContentFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesValueIsString_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":\"a\"}"); + PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":\"a\"}", environmentVariableReader); Assert.Empty(packageSpec.ContentFiles); } [Theory] - [InlineData("")] - [InlineData("/**/")] - public void GetPackageSpec_WhenContentFilesValueIsEmptyArray_ReturnsEmptyContentFiles(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "/**/", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesValueIsEmptyArray_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader, string value) { - PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}", environmentVariableReader); Assert.Empty(packageSpec.ContentFiles); } [Theory] - [InlineData("{}")] - [InlineData("[]")] - public void GetPackageSpec_WhenContentFilesValueElementIsNotConvertibleToString_Throws(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[]", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesValueElementIsNotConvertibleToString_Throws(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"contentFiles\":[{value}]}}"; - Assert.Throws(() => GetPackageSpec(json)); + Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("true", "True")] - [InlineData("-2", "-2")] - [InlineData("3.14", "3.14")] - public void GetPackageSpec_WhenContentFilesValueElementIsConvertibleToString_ReturnsContentFile(string value, string expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenContentFilesValueElementIsConvertibleToString_ReturnsContentFile(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { - PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}", environmentVariableReader); Assert.Collection(packageSpec.ContentFiles, contentFile => Assert.Equal(expectedValue, contentFile)); } - [Fact] - public void GetPackageSpec_WhenCopyrightPropertyIsAbsent_ReturnsNullCopyright() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenCopyrightPropertyIsAbsent_ReturnsNullCopyright(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Null(packageSpec.Copyright); } - [Fact] - public void GetPackageSpec_WhenCopyrightValueIsNull_ReturnsNullCopyright() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenCopyrightValueIsNull_ReturnsNullCopyright(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"copyright\":null}"); + PackageSpec packageSpec = GetPackageSpec("{\"copyright\":null}", environmentVariableReader); Assert.Null(packageSpec.Copyright); } - [Fact] - public void GetPackageSpec_WhenCopyrightValueIsString_ReturnsCopyright() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenCopyrightValueIsString_ReturnsCopyright(IEnvironmentVariableReader environmentVariableReader) { const string expectedResult = "a"; - PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":\"{expectedResult}\"}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":\"{expectedResult}\"}}", environmentVariableReader); Assert.Equal(expectedResult, packageSpec.Copyright); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("true", "True")] - [InlineData("-2", "-2")] - [InlineData("3.14", "3.14")] - public void GetPackageSpec_WhenCopyrightValueIsConvertibleToString_ReturnsCopyright(string value, string expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenCopyrightValueIsConvertibleToString_ReturnsCopyright(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { - PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":{value}}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":{value}}}", environmentVariableReader); Assert.Equal(expectedValue, packageSpec.Copyright); } #pragma warning restore CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenDependenciesPropertyIsAbsent_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesPropertyIsAbsent_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Empty(packageSpec.Dependencies); } - [Fact] - public void GetPackageSpec_WhenDependenciesValueIsNull_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesValueIsNull_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"dependencies\":null}"); + PackageSpec packageSpec = GetPackageSpec("{\"dependencies\":null}", environmentVariableReader); Assert.Empty(packageSpec.Dependencies); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyNameIsEmptyString_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyNameIsEmptyString_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"\":{}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); - + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); Assert.Equal("Unable to resolve dependency ''.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(21, exception.Column); Assert.Null(exception.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(1, exception.Line); + Assert.Equal(21, exception.Column); + } } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionString_ReturnsDependencyVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionString_ReturnsDependencyVersionRange(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new LibraryRange( name: "a", @@ -1193,13 +1254,14 @@ public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionString_Return LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference); var json = $"{{\"dependencies\":{{\"{expectedResult.Name}\":\"{expectedResult.VersionRange.ToShortString()}\"}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.LibraryRange); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionRangeString_ReturnsDependencyVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionRangeString_ReturnsDependencyVersionRange(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new LibraryRange( name: "a", @@ -1207,207 +1269,238 @@ public void GetPackageSpec_WhenDependenciesDependencyValueIsVersionRangeString_R LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference); var json = $"{{\"dependencies\":{{\"{expectedResult.Name}\":\"{expectedResult.VersionRange}\"}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.LibraryRange); } [Theory] - [InlineData(LibraryDependencyTarget.None)] - [InlineData(LibraryDependencyTarget.Assembly)] - [InlineData(LibraryDependencyTarget.Reference)] - [InlineData(LibraryDependencyTarget.WinMD)] - [InlineData(LibraryDependencyTarget.All)] - [InlineData(LibraryDependencyTarget.PackageProjectExternal)] - public void GetPackageSpec_WhenDependenciesDependencyTargetIsUnsupported_Throws(LibraryDependencyTarget target) + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.None, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.Assembly, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.Reference, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.WinMD, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.All, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.PackageProjectExternal, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyTargetIsUnsupported_Throws(IEnvironmentVariableReader environmentVariableReader, LibraryDependencyTarget target) { var json = $"{{\"dependencies\":{{\"a\":{{\"version\":\"1.2.3\",\"target\":\"{target}\"}}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); Assert.Equal($"Invalid dependency target value '{target}'.", exception.Message); - Assert.Equal(1, exception.Line); - // The position is after the target name, which is of variable length. - Assert.Equal(json.IndexOf(target.ToString()) + target.ToString().Length + 1, exception.Column); Assert.Null(exception.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(1, exception.Line); + // The position is after the target name, which is of variable length. + Assert.Equal(json.IndexOf(target.ToString()) + target.ToString().Length + 1, exception.Column); + } } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyAutoreferencedPropertyIsAbsent_ReturnsFalseAutoreferenced() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyAutoreferencedPropertyIsAbsent_ReturnsFalseAutoreferenced(IEnvironmentVariableReader environmentVariableReader) { - LibraryDependency dependency = GetDependency($"{{\"dependencies\":{{\"a\":{{\"target\":\"Project\"}}}}}}"); + LibraryDependency dependency = GetDependency($"{{\"dependencies\":{{\"a\":{{\"target\":\"Project\"}}}}}}", environmentVariableReader); Assert.False(dependency.AutoReferenced); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenDependenciesDependencyAutoreferencedValueIsBool_ReturnsBoolAutoreferenced(bool expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyAutoreferencedValueIsBool_ReturnsBoolAutoreferenced(IEnvironmentVariableReader environmentVariableReader, bool expectedValue) { var json = $"{{\"dependencies\":{{\"a\":{{\"autoReferenced\":{expectedValue.ToString().ToLower()},\"target\":\"Project\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedValue, dependency.AutoReferenced); } [Theory] - [InlineData("exclude")] - [InlineData("include")] - [InlineData("suppressParent")] - public void GetPackageSpec_WhenDependenciesDependencyValueIsArray_Throws(string propertyName) + [MemberData(nameof(TestEnvironmentVariableReader), "exclude", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "include", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "suppressParent", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyValueIsArray_Throws(IEnvironmentVariableReader environmentVariableReader, string propertyName) { var json = $"{{\"dependencies\":{{\"a\":{{\"{propertyName}\":[\"b\"]}}}}}}"; - Assert.Throws(() => GetPackageSpec(json)); + Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyIncludeAndExcludePropertiesAreAbsent_ReturnsAllIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyIncludeAndExcludePropertiesAreAbsent_ReturnsAllIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.All, dependency.IncludeType); } [Theory] - [InlineData("\"Native\"", LibraryIncludeFlags.Native)] - [InlineData("\"Analyzers, Native\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Native)] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Native\"", LibraryIncludeFlags.Native, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Analyzers, Native\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Native, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenDependenciesDependencyExcludeValueIsValid_ReturnsIncludeType( + IEnvironmentVariableReader environmentVariableReader, string value, LibraryIncludeFlags result) { var json = $"{{\"dependencies\":{{\"a\":{{\"exclude\":{value},\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.All & ~result, dependency.IncludeType); } [Theory] - [InlineData("\"Native\"", LibraryIncludeFlags.Native)] - [InlineData("\"Analyzers, Native\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Native)] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Native\"", LibraryIncludeFlags.Native, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Analyzers, Native\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Native, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenDependenciesDependencyIncludeValueIsValid_ReturnsIncludeType( + IEnvironmentVariableReader environmentVariableReader, string value, LibraryIncludeFlags expectedResult) { var json = $"{{\"dependencies\":{{\"a\":{{\"include\":{value},\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyIncludeValueOverridesTypeValue_ReturnsIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyIncludeValueOverridesTypeValue_ReturnsIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"include\":\"ContentFiles\",\"type\":\"BecomesNupkgDependency, SharedFramework\",\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.ContentFiles, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencySuppressParentValueOverridesTypeValue_ReturnsSuppressParent() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencySuppressParentValueOverridesTypeValue_ReturnsSuppressParent(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"suppressParent\":\"ContentFiles\",\"type\":\"SharedFramework\",\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.ContentFiles, dependency.SuppressParent); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencySuppressParentPropertyIsAbsent_ReturnsSuppressParent() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencySuppressParentPropertyIsAbsent_ReturnsSuppressParent(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlagUtils.DefaultSuppressParent, dependency.SuppressParent); } [Theory] - [InlineData("\"Compile\"", LibraryIncludeFlags.Compile)] - [InlineData("\"Analyzers, Compile\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Compile)] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Compile\"", LibraryIncludeFlags.Compile, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"Analyzers, Compile\"", LibraryIncludeFlags.Analyzers | LibraryIncludeFlags.Compile, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenDependenciesDependencySuppressParentValueIsValid_ReturnsSuppressParent( + IEnvironmentVariableReader environmentVariableReader, string value, - LibraryIncludeFlags expectedResult) + LibraryIncludeFlags expectedResult + ) { var json = $"{{\"dependencies\":{{\"a\":{{\"suppressParent\":{value},\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.SuppressParent); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyVersionValueIsInvalid_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyVersionValueIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"b\"}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 35 : 'b' is not a valid version string.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(35, exception.Column); - Assert.IsType(exception.InnerException); - Assert.Null(exception.InnerException.InnerException); + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 35 : 'b' is not a valid version string.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(35, exception.Column); + } + else + { + Assert.Equal("Error reading '' : 'b' is not a valid version string.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyTargetPropertyIsAbsent_ReturnsTarget() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyTargetPropertyIsAbsent_ReturnsTarget(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"target\":\"Package\"}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); - - Assert.Equal("Error reading '' at line 1 column 22 : Package dependencies must specify a version range.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(22, exception.Column); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 22 : Package dependencies must specify a version range.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(22, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Package dependencies must specify a version range.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange(IEnvironmentVariableReader environmentVariableReader) { - LibraryDependency dependency = GetDependency("{\"dependencies\":{\"a\":{\"target\":\"Project\"}}}"); + LibraryDependency dependency = GetDependency("{\"dependencies\":{\"a\":{\"target\":\"Project\"}}}", environmentVariableReader); Assert.Equal(VersionRange.All, dependency.LibraryRange.VersionRange); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyNoWarnPropertyIsAbsent_ReturnsEmptyNoWarns() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyNoWarnPropertyIsAbsent_ReturnsEmptyNoWarns(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Empty(dependency.NoWarn); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyNoWarnValueIsValid_ReturnsNoWarns() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyNoWarnValueIsValid_ReturnsNoWarns(IEnvironmentVariableReader environmentVariableReader) { NuGetLogCode[] expectedResults = { NuGetLogCode.NU1000, NuGetLogCode.NU3000 }; var json = $"{{\"dependencies\":{{\"a\":{{\"noWarn\":[\"{expectedResults[0].ToString()}\",\"{expectedResults[1].ToString()}\"],\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Collection( dependency.NoWarn, @@ -1415,144 +1508,153 @@ public void GetPackageSpec_WhenDependenciesDependencyNoWarnValueIsValid_ReturnsN noWarn => Assert.Equal(expectedResults[1], noWarn)); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyGeneratePathPropertyPropertyIsAbsent_ReturnsFalseGeneratePathProperty() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyGeneratePathPropertyPropertyIsAbsent_ReturnsFalseGeneratePathProperty(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.False(dependency.GeneratePathProperty); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenDependenciesDependencyGeneratePathPropertyValueIsValid_ReturnsGeneratePathProperty(bool expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyGeneratePathPropertyValueIsValid_ReturnsGeneratePathProperty(IEnvironmentVariableReader environmentVariableReader, bool expectedResult) { var json = $"{{\"dependencies\":{{\"a\":{{\"generatePathProperty\":{expectedResult.ToString().ToLowerInvariant()},\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.GeneratePathProperty); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyTypePropertyIsAbsent_ReturnsDefaultTypeConstraint() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyTypePropertyIsAbsent_ReturnsDefaultTypeConstraint(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"dependencies\":{\"a\":{\"version\":\"1.0.0\"}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal( LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void GetPackageSpec_WhenDependenciesDependencyVersionCentrallyManagedPropertyIsAbsent_ReturnsFalseVersionCentrallyManaged() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyVersionCentrallyManagedPropertyIsAbsent_ReturnsFalseVersionCentrallyManaged(IEnvironmentVariableReader environmentVariableReader) { - LibraryDependency dependency = GetDependency($"{{\"dependencies\":{{\"a\":{{\"target\":\"Package\",\"version\":\"1.0.0\"}}}}}}"); + LibraryDependency dependency = GetDependency($"{{\"dependencies\":{{\"a\":{{\"target\":\"Package\",\"version\":\"1.0.0\"}}}}}}", environmentVariableReader); Assert.False(dependency.VersionCentrallyManaged); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenDependenciesDependencyVersionCentrallyManagedValueIsBool_ReturnsBoolVersionCentrallyManaged(bool expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDependenciesDependencyVersionCentrallyManagedValueIsBool_ReturnsBoolVersionCentrallyManaged(IEnvironmentVariableReader environmentVariableReader, bool expectedValue) { var json = $"{{\"dependencies\":{{\"a\":{{\"versionCentrallyManaged\":{expectedValue.ToString().ToLower()},\"target\":\"Package\",\"version\":\"1.0.0\"}}}}}}"; - LibraryDependency dependency = GetDependency(json); + LibraryDependency dependency = GetDependency(json, environmentVariableReader); Assert.Equal(expectedValue, dependency.VersionCentrallyManaged); } #pragma warning disable CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenDescriptionPropertyIsAbsent_ReturnsNullDescription() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDescriptionPropertyIsAbsent_ReturnsNullDescription(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Null(packageSpec.Description); } [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("b")] - public void GetPackageSpec_WhenDescriptionValueIsValid_ReturnsDescription(string expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenDescriptionValueIsValid_ReturnsDescription(IEnvironmentVariableReader environmentVariableReader, string expectedResult) { string description = expectedResult == null ? "null" : $"\"{expectedResult}\""; - PackageSpec packageSpec = GetPackageSpec($"{{\"description\":{description}}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"description\":{description}}}", environmentVariableReader); Assert.Equal(expectedResult, packageSpec.Description); } - [Fact] - public void GetPackageSpec_WhenLanguagePropertyIsAbsent_ReturnsNullLanguage() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenLanguagePropertyIsAbsent_ReturnsNullLanguage(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Null(packageSpec.Language); } [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("b")] - public void GetPackageSpec_WhenLanguageValueIsValid_ReturnsLanguage(string expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenLanguageValueIsValid_ReturnsLanguage(IEnvironmentVariableReader environmentVariableReader, string expectedResult) { string language = expectedResult == null ? "null" : $"\"{expectedResult}\""; - PackageSpec packageSpec = GetPackageSpec($"{{\"language\":{language}}}"); + PackageSpec packageSpec = GetPackageSpec($"{{\"language\":{language}}}", environmentVariableReader); Assert.Equal(expectedResult, packageSpec.Language); } #pragma warning restore CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenFrameworksPropertyIsAbsent_ReturnsEmptyFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksPropertyIsAbsent_ReturnsEmptyFrameworks(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Empty(packageSpec.TargetFrameworks); } - [Fact] - public void GetPackageSpec_WhenFrameworksValueIsEmptyObject_ReturnsEmptyFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksValueIsEmptyObject_ReturnsEmptyFrameworks(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{\"frameworks\":{}}"); + PackageSpec packageSpec = GetPackageSpec("{\"frameworks\":{}}", environmentVariableReader); Assert.Empty(packageSpec.TargetFrameworks); } - [Fact] - public void GetPackageSpec_WhenFrameworksAssetTargetFallbackPropertyIsAbsent_ReturnsFalseAssetTargetFallback() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksAssetTargetFallbackPropertyIsAbsent_ReturnsFalseAssetTargetFallback(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}", environmentVariableReader); Assert.False(framework.AssetTargetFallback); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenFrameworksAssetTargetFallbackValueIsValid_ReturnsAssetTargetFallback(bool expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksAssetTargetFallbackValueIsValid_ReturnsAssetTargetFallback(IEnvironmentVariableReader environmentVariableReader, bool expectedValue) { var json = $"{{\"frameworks\":{{\"a\":{{\"assetTargetFallback\":{expectedValue.ToString().ToLowerInvariant()}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Equal(expectedValue, framework.AssetTargetFallback); } - [Fact] - public void GetPackageSpec_WithAssetTargetFallbackAndImportsValues_ReturnsValidAssetTargetFallbackFramework() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WithAssetTargetFallbackAndImportsValues_ReturnsValidAssetTargetFallbackFramework(IEnvironmentVariableReader environmentVariableReader) { var json = $"{{\"frameworks\":{{\"net5.0\":{{\"assetTargetFallback\": true, \"imports\": [\"net472\", \"net471\"]}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); framework.AssetTargetFallback.Should().BeTrue(); var assetTargetFallback = framework.FrameworkName as AssetTargetFallbackFramework; @@ -1562,61 +1664,81 @@ public void GetPackageSpec_WithAssetTargetFallbackAndImportsValues_ReturnsValidA assetTargetFallback.Fallback.Last().Should().Be(FrameworkConstants.CommonFrameworks.Net471); } - [Fact] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsPropertyIsAbsent_ReturnsEmptyCentralPackageVersions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsPropertyIsAbsent_ReturnsEmptyCentralPackageVersions(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}", environmentVariableReader); Assert.Empty(framework.CentralPackageVersions); } - [Fact] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsValueIsEmptyObject_ReturnsEmptyCentralPackageVersions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsValueIsEmptyObject_ReturnsEmptyCentralPackageVersions(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{\"centralPackageVersions\":{}}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{\"centralPackageVersions\":{}}}}", environmentVariableReader); Assert.Empty(framework.CentralPackageVersions); } - [Fact] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsVersionPropertyNameIsEmptyString_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsVersionPropertyNameIsEmptyString_Throws(IEnvironmentVariableReader environmentVariableReader) { var json = "{\"frameworks\":{\"a\":{\"centralPackageVersions\":{\"\":\"1.0.0\"}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve central version ''.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve central version ''.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Unable to resolve central version ''.", exception.Message); + } } [Theory] - [InlineData("null")] - [InlineData("\"\"")] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsVersionPropertyValueIsNullOrEmptyString_Throws(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "null", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsVersionPropertyValueIsNullOrEmptyString_Throws(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"frameworks\":{{\"a\":{{\"centralPackageVersions\":{{\"b\":{value}}}}}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : The version cannot be null or empty.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : The version cannot be null or empty.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : The version cannot be null or empty.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsIsValid_ReturnsCentralPackageVersions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsIsValid_ReturnsCentralPackageVersions(IEnvironmentVariableReader environmentVariableReader) { const string expectedPackageId = "b"; VersionRange expectedVersionRange = VersionRange.Parse("[1.2.3,4.5.6)"); var expectedCentralPackageVersion = new CentralPackageVersion(expectedPackageId, expectedVersionRange); var json = $"{{\"frameworks\":{{\"a\":{{\"centralPackageVersions\":{{\"{expectedPackageId}\":\"{expectedVersionRange.ToShortString()}\"}}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Collection( framework.CentralPackageVersions, @@ -1627,8 +1749,9 @@ public void GetPackageSpec_WhenFrameworksCentralPackageVersionsIsValid_ReturnsCe }); } - [Fact] - public void GetPackageSpec_WhenFrameworksCentralPackageVersionsHasDuplicateKey_LastOneWins() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksCentralPackageVersionsHasDuplicateKey_LastOneWins(IEnvironmentVariableReader environmentVariableReader) { const string expectedPackageId = "b"; VersionRange unexpectedVersionRange = VersionRange.Parse("1.2.3"); @@ -1637,7 +1760,7 @@ public void GetPackageSpec_WhenFrameworksCentralPackageVersionsHasDuplicateKey_L var json = $"{{\"frameworks\":{{\"a\":{{\"centralPackageVersions\":{{\"{expectedPackageId}\":\"{unexpectedVersionRange.ToShortString()}\"," + $"\"{expectedPackageId}\":\"{expectedVersionRange.ToShortString()}\"}}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Collection( framework.CentralPackageVersions, @@ -1648,38 +1771,49 @@ public void GetPackageSpec_WhenFrameworksCentralPackageVersionsHasDuplicateKey_L }); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesPropertyIsAbsent_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesPropertyIsAbsent_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{}}}", environmentVariableReader); Assert.Empty(framework.Dependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesValueIsNull_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesValueIsNull_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{\"dependencies\":null}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"a\":{\"dependencies\":null}}}", environmentVariableReader); Assert.Empty(framework.Dependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyNameIsEmptyString_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyNameIsEmptyString_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"\":{}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve dependency ''.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve dependency ''.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Unable to resolve dependency ''.", exception.Message); + } Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionString_ReturnsDependencyVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionString_ReturnsDependencyVersionRange(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new LibraryRange( name: "b", @@ -1687,13 +1821,14 @@ public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionStr LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference); var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"{expectedResult.Name}\":\"{expectedResult.VersionRange.ToShortString()}\"}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.LibraryRange); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionRangeString_ReturnsDependencyVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionRangeString_ReturnsDependencyVersionRange(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new LibraryRange( name: "b", @@ -1701,211 +1836,257 @@ public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsVersionRan LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference); var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"{expectedResult.Name}\":\"{expectedResult.VersionRange}\"}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.LibraryRange); } [Theory] - [InlineData(LibraryDependencyTarget.None)] - [InlineData(LibraryDependencyTarget.Assembly)] - [InlineData(LibraryDependencyTarget.Reference)] - [InlineData(LibraryDependencyTarget.WinMD)] - [InlineData(LibraryDependencyTarget.All)] - [InlineData(LibraryDependencyTarget.PackageProjectExternal)] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsUnsupported_Throws(LibraryDependencyTarget target) + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.None, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.Assembly, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.Reference, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.WinMD, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.All, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), LibraryDependencyTarget.PackageProjectExternal, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsUnsupported_Throws(IEnvironmentVariableReader environmentVariableReader, LibraryDependencyTarget target) { var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"version\":\"1.2.3\",\"target\":\"{target}\"}}}}}}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal($"Error reading '' at line 1 column 20 : Invalid dependency target value '{target}'.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal($"Error reading '' at line 1 column 20 : Invalid dependency target value '{target}'.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal($"Error reading '' : Invalid dependency target value '{target}'.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyAutoreferencedPropertyIsAbsent_ReturnsFalseAutoreferenced() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyAutoreferencedPropertyIsAbsent_ReturnsFalseAutoreferenced(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"target\":\"Project\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.False(dependency.AutoReferenced); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyAutoreferencedValueIsBool_ReturnsBoolAutoreferenced(bool expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyAutoreferencedValueIsBool_ReturnsBoolAutoreferenced(IEnvironmentVariableReader environmentVariableReader, bool expectedValue) { var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"autoReferenced\":{expectedValue.ToString().ToLower()},\"target\":\"Project\"}}}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(expectedValue, dependency.AutoReferenced); } [Theory] - [InlineData("exclude")] - [InlineData("include")] - [InlineData("suppressParent")] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsArray_Throws(string propertyName) + [MemberData(nameof(TestEnvironmentVariableReader), "exclude", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "include", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "suppressParent", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyValueIsArray_Throws(IEnvironmentVariableReader environmentVariableReader, string propertyName) { var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"{propertyName}\":[\"c\"]}}}}}}}}}}"; // The exception messages will not be the same because the innermost exception in the baseline // is a Newtonsoft.Json exception, while it's a .NET exception in the improved. - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Specified cast is not valid.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Specified cast is not valid.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Specified cast is not valid.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeAndExcludePropertiesAreAbsent_ReturnsAllIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeAndExcludePropertiesAreAbsent_ReturnsAllIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.All, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyExcludeValueIsValid_ReturnsIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyExcludeValueIsValid_ReturnsIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"exclude\":\"Native\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.All & ~LibraryIncludeFlags.Native, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeValueIsValid_ReturnsIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeValueIsValid_ReturnsIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"include\":\"ContentFiles\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.ContentFiles, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeValueOverridesTypeValue_ReturnsIncludeType() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyIncludeValueOverridesTypeValue_ReturnsIncludeType(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"include\":\"ContentFiles\",\"type\":\"BecomesNupkgDependency, SharedFramework\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.ContentFiles, dependency.IncludeType); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentValueOverridesTypeValue_ReturnsSuppressParent() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentValueOverridesTypeValue_ReturnsSuppressParent(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"suppressParent\":\"ContentFiles\",\"type\":\"SharedFramework\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.ContentFiles, dependency.SuppressParent); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentPropertyIsAbsent_ReturnsSuppressParent() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentPropertyIsAbsent_ReturnsSuppressParent(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlagUtils.DefaultSuppressParent, dependency.SuppressParent); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentValueIsValid_ReturnsSuppressParent() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencySuppressParentValueIsValid_ReturnsSuppressParent(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"suppressParent\":\"Compile\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryIncludeFlags.Compile, dependency.SuppressParent); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionValueIsInvalid_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionValueIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"c\"}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 54 : 'c' is not a valid version string.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.IsType(exception.InnerException.InnerException); Assert.Null(exception.InnerException.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 54 : 'c' is not a valid version string.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Error reading '' : 'c' is not a valid version string.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetPropertyIsAbsent_ReturnsTarget() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetPropertyIsAbsent_ReturnsTarget(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal( LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"target\":\"Package\"}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 41 : Package dependencies must specify a version range.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.IsType(exception.InnerException.InnerException); Assert.Null(exception.InnerException.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 41 : Package dependencies must specify a version range.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Error reading '' : Package dependencies must specify a version range.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"target\":\"Project\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(VersionRange.All, dependency.LibraryRange.VersionRange); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyNoWarnPropertyIsAbsent_ReturnsEmptyNoWarns() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyNoWarnPropertyIsAbsent_ReturnsEmptyNoWarns(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Empty(dependency.NoWarn); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyNoWarnValueIsValid_ReturnsNoWarns() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyNoWarnValueIsValid_ReturnsNoWarns(IEnvironmentVariableReader environmentVariableReader) { NuGetLogCode[] expectedResults = { NuGetLogCode.NU1000, NuGetLogCode.NU3000 }; var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"noWarn\":[\"{expectedResults[0].ToString()}\",\"{expectedResults[1].ToString()}\"],\"version\":\"1.0.0\"}}}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Collection( dependency.NoWarn, @@ -1913,34 +2094,36 @@ public void GetPackageSpec_WhenFrameworksDependenciesDependencyNoWarnValueIsVali noWarn => Assert.Equal(expectedResults[1], noWarn)); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyGeneratePathPropertyPropertyIsAbsent_ReturnsFalseGeneratePathProperty() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyGeneratePathPropertyPropertyIsAbsent_ReturnsFalseGeneratePathProperty(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.False(dependency.GeneratePathProperty); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyGeneratePathPropertyValueIsValid_ReturnsGeneratePathProperty(bool expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyGeneratePathPropertyValueIsValid_ReturnsGeneratePathProperty(IEnvironmentVariableReader environmentVariableReader, bool expectedResult) { var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"generatePathProperty\":{expectedResult.ToString().ToLowerInvariant()},\"version\":\"1.0.0\"}}}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(expectedResult, dependency.GeneratePathProperty); } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyTypePropertyIsAbsent_ReturnsDefaultTypeConstraint() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyTypePropertyIsAbsent_ReturnsDefaultTypeConstraint(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal( LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference, @@ -1948,89 +2131,103 @@ public void GetPackageSpec_WhenFrameworksDependenciesDependencyTypePropertyIsAbs } - [Fact] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionCentrallyManagedPropertyIsAbsent_ReturnsFalseVersionCentrallyManaged() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionCentrallyManagedPropertyIsAbsent_ReturnsFalseVersionCentrallyManaged(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"dependencies\":{\"b\":{\"target\":\"Package\",\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.False(dependency.VersionCentrallyManaged); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionCentrallyManagedValueIsBool_ReturnsBoolVersionCentrallyManaged(bool expectedValue) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDependenciesDependencyVersionCentrallyManagedValueIsBool_ReturnsBoolVersionCentrallyManaged(IEnvironmentVariableReader environmentVariableReader, bool expectedValue) { var json = $"{{\"frameworks\":{{\"a\":{{\"dependencies\":{{\"b\":{{\"versionCentrallyManaged\":{expectedValue.ToString().ToLower()},\"target\":\"Package\",\"version\":\"1.0.0\"}}}}}}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(expectedValue, dependency.VersionCentrallyManaged); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesPropertyIsAbsent_ReturnsEmptyDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesPropertyIsAbsent_ReturnsEmptyDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.DownloadDependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsNull_ReturnsEmptyDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsNull_ReturnsEmptyDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"downloadDependencies\":null}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.DownloadDependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsNotArray_ReturnsEmptyDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsNotArray_ReturnsEmptyDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"downloadDependencies\":\"b\"}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.DownloadDependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsEmptyArray_ReturnsEmptyDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsEmptyArray_ReturnsEmptyDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"downloadDependencies\":[]}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.DownloadDependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyNameIsAbsent_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyNameIsAbsent_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"downloadDependencies\":[{\"version\":\"1.2.3\"}]}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); - - Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve downloadDependency ''.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve downloadDependency ''.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Unable to resolve downloadDependency ''.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyNameIsNull_ReturnsDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyNameIsNull_ReturnsDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new DownloadDependency(name: null, new VersionRange(new NuGetVersion("1.2.3"))); var json = $"{{\"frameworks\":{{\"a\":{{\"downloadDependencies\":[{{\"name\":null,\"version\":\"{expectedResult.VersionRange.ToShortString()}\"}}]}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); DownloadDependency actualResult = framework.DownloadDependencies.Single(); @@ -2038,52 +2235,86 @@ public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyNameIsNul Assert.Equal(expectedResult.VersionRange, actualResult.VersionRange); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyVersionIsAbsent_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyVersionIsAbsent_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"downloadDependencies\":[{\"name\":\"b\"}]}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : The version cannot be null or empty", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : The version cannot be null or empty", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : The version cannot be null or empty", exception.Message); + } } [Theory] - [InlineData("null")] - [InlineData("c")] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyVersionIsInvalid_Throws(string version) + [MemberData(nameof(TestEnvironmentVariableReader), "null", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "c", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesDependencyVersionIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader, string version) { var json = $"{{\"frameworks\":{{\"a\":{{\"downloadDependencies\":[{{\"name\":\"b\",\"version\":\"{version}\"}}]}}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); int expectedColumn = json.IndexOf($"\"{version}\"") + version.Length + 2; - Assert.Equal($"Error reading '' at line 1 column 20 : Error reading '' at line 1 column {expectedColumn} : '{version}' is not a valid version string.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.IsType(exception.InnerException.InnerException); Assert.Null(exception.InnerException.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal($"Error reading '' at line 1 column 20 : Error reading '' at line 1 column {expectedColumn} : '{version}' is not a valid version string.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal($"Error reading '' : Error reading '' : '{version}' is not a valid version string.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsValid_ReturnsDownloadDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsValid_ReturnsDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new DownloadDependency(name: "b", new VersionRange(new NuGetVersion("1.2.3"))); var json = $"{{\"frameworks\":{{\"a\":{{\"downloadDependencies\":[{{\"name\":\"{expectedResult.Name}\",\"version\":\"{expectedResult.VersionRange.ToShortString()}\"}}]}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Equal(expectedResult, framework.DownloadDependencies.Single()); } - [Fact] - public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueHasDuplicates_PrefersFirstByName() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueIsValidWithMultipleVersions_ReturnsDownloadDependencies(IEnvironmentVariableReader environmentVariableReader) + { + var json = $"{{\"frameworks\":{{\"a\":{{\"downloadDependencies\":[{{\"name\":\"b\",\"version\":\"1.2.3;;2.0.0\"}}]}}}}}}"; + + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); + + Assert.Equal(2, framework.DownloadDependencies.Count()); + Assert.Equal("b", framework.DownloadDependencies[0].Name); + Assert.Equal(new VersionRange(new NuGetVersion("1.2.3")), framework.DownloadDependencies[0].VersionRange); + Assert.Equal("b", framework.DownloadDependencies[1].Name); + Assert.Equal(new VersionRange(new NuGetVersion("2.0.0")), framework.DownloadDependencies[1].VersionRange); + + } + + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueHasDuplicates_PrefersFirstByName(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new DownloadDependency(name: "b", new VersionRange(new NuGetVersion("1.2.3"))); var unexpectedResult = new DownloadDependency(name: "b", new VersionRange(new NuGetVersion("4.5.6"))); @@ -2092,251 +2323,295 @@ public void GetPackageSpec_WhenFrameworksDownloadDependenciesValueHasDuplicates_ $"{{\"name\":\"{unexpectedResult.Name}\",\"version\":\"{unexpectedResult.VersionRange.ToShortString()}\"}}" + "]}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Equal(expectedResult, framework.DownloadDependencies.Single()); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesPropertyIsAbsent_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesPropertyIsAbsent_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Dependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesValueIsNull_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesValueIsNull_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkAssemblies\":null}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Dependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesValueIsEmptyObject_ReturnsEmptyDependencies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesValueIsEmptyObject_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkAssemblies\":{}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Dependencies); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetPropertyIsAbsent_ReturnsTarget() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetPropertyIsAbsent_ReturnsTarget(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkAssemblies\":{\"b\":{\"version\":\"1.0.0\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(LibraryDependencyTarget.Reference, dependency.LibraryRange.TypeConstraint); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetValueIsPackageAndVersionPropertyIsAbsent_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkAssemblies\":{\"b\":{\"target\":\"Package\"}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 48 : Package dependencies must specify a version range.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.IsType(exception.InnerException.InnerException); Assert.Null(exception.InnerException.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Error reading '' at line 1 column 48 : Package dependencies must specify a version range.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Error reading '' : Package dependencies must specify a version range.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkAssembliesDependencyTargetValueIsProjectAndVersionPropertyIsAbsent_ReturnsAllVersionRange(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkAssemblies\":{\"b\":{\"target\":\"Project\"}}}}}"; - LibraryDependency dependency = GetFrameworksDependency(json); + LibraryDependency dependency = GetFrameworksDependency(json, environmentVariableReader); Assert.Equal(VersionRange.All, dependency.LibraryRange.VersionRange); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesPropertyIsAbsent_ReturnsEmptyFrameworkReferences() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesPropertyIsAbsent_ReturnsEmptyFrameworkReferences(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.FrameworkReferences); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesValueIsNull_ReturnsEmptyFrameworkReferences() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesValueIsNull_ReturnsEmptyFrameworkReferences(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkReferences\":null}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.FrameworkReferences); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesValueIsEmptyObject_ReturnsEmptyFrameworkReferences() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesValueIsEmptyObject_ReturnsEmptyFrameworkReferences(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkReferences\":{}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.FrameworkReferences); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesFrameworkNameIsEmptyString_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesFrameworkNameIsEmptyString_Throws(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"frameworkReferences\":{\"\":{}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve frameworkReference.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal("Error reading '' at line 1 column 20 : Unable to resolve frameworkReference.", exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal("Error reading '' : Unable to resolve frameworkReference.", exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsPropertyIsAbsent_ReturnsNonePrivateAssets() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsPropertyIsAbsent_ReturnsNonePrivateAssets(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new FrameworkDependency(name: "b", FrameworkDependencyFlags.None); var json = $"{{\"frameworks\":{{\"a\":{{\"frameworkReferences\":{{\"{expectedResult.Name}\":{{}}}}}}}}}}"; - FrameworkDependency dependency = GetFrameworksFrameworkReference(json); + FrameworkDependency dependency = GetFrameworksFrameworkReference(json, environmentVariableReader); Assert.Equal(expectedResult, dependency); } [Theory] - [InlineData("\"null\"")] - [InlineData("\"\"")] - [InlineData("\"c\"")] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsInvalidValue_ReturnsNonePrivateAssets(string privateAssets) + [MemberData(nameof(TestEnvironmentVariableReader), "\"null\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"c\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsInvalidValue_ReturnsNonePrivateAssets(IEnvironmentVariableReader environmentVariableReader, string privateAssets) { var expectedResult = new FrameworkDependency(name: "b", FrameworkDependencyFlags.None); var json = $"{{\"frameworks\":{{\"a\":{{\"frameworkReferences\":{{\"{expectedResult.Name}\":{{\"privateAssets\":{privateAssets}}}}}}}}}}}"; - FrameworkDependency dependency = GetFrameworksFrameworkReference(json); + FrameworkDependency dependency = GetFrameworksFrameworkReference(json, environmentVariableReader); Assert.Equal(expectedResult, dependency); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsValidString_ReturnsPrivateAssets() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsValidString_ReturnsPrivateAssets(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new FrameworkDependency(name: "b", FrameworkDependencyFlags.All); var json = $"{{\"frameworks\":{{\"a\":{{\"frameworkReferences\":{{\"{expectedResult.Name}\":{{\"privateAssets\":\"{expectedResult.PrivateAssets.ToString().ToLowerInvariant()}\"}}}}}}}}}}"; - FrameworkDependency dependency = GetFrameworksFrameworkReference(json); + FrameworkDependency dependency = GetFrameworksFrameworkReference(json, environmentVariableReader); Assert.Equal(expectedResult, dependency); } - [Fact] - public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsValidDelimitedString_ReturnsPrivateAssets() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksFrameworkReferencesPrivateAssetsValueIsValidDelimitedString_ReturnsPrivateAssets(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new FrameworkDependency(name: "b", FrameworkDependencyFlags.All); var json = $"{{\"frameworks\":{{\"a\":{{\"frameworkReferences\":{{\"{expectedResult.Name}\":{{\"privateAssets\":\"none,all\"}}}}}}}}}}"; - FrameworkDependency dependency = GetFrameworksFrameworkReference(json); + FrameworkDependency dependency = GetFrameworksFrameworkReference(json, environmentVariableReader); Assert.Equal(expectedResult, dependency); } - [Fact] - public void GetPackageSpec_WhenFrameworksImportsPropertyIsAbsent_ReturnsEmptyImports() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsPropertyIsAbsent_ReturnsEmptyImports(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Imports); } [Theory] - [InlineData("null")] - [InlineData("\"\"")] - public void GetPackageSpec_WhenFrameworksImportsValueIsArrayOfNullOrEmptyString_ImportIsSkipped(string import) + [MemberData(nameof(TestEnvironmentVariableReader), "null", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueIsArrayOfNullOrEmptyString_ImportIsSkipped(IEnvironmentVariableReader environmentVariableReader, string import) { var json = $"{{\"frameworks\":{{\"a\":{{\"imports\":[{import}]}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Imports); } - [Fact] - public void GetPackageSpec_WhenFrameworksImportsValueIsNull_ReturnsEmptyList() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueIsNull_ReturnsEmptyList(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{\"imports\":null}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Imports); } [Theory] - [InlineData("true")] - [InlineData("-2")] - [InlineData("3.14")] - [InlineData("{}")] - public void GetPackageSpec_WhenFrameworksImportsValueIsInvalidValue_ReturnsEmptyList(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "true", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueIsInvalidValue_ReturnsEmptyList(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"frameworks\":{{\"a\":{{\"imports\":{value}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Empty(framework.Imports); } - [Fact] - public void GetPackageSpec_WhenFrameworksImportsValueContainsInvalidValue_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueContainsInvalidValue_Throws(IEnvironmentVariableReader environmentVariableReader) { const string expectedImport = "b"; var json = $"{{\"frameworks\":{{\"a\":{{\"imports\":[\"{expectedImport}\"]}}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal( - $"Error reading '' at line 1 column 20 : Imports contains an invalid framework: '{expectedImport}' in 'project.json'.", - exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(20, exception.Column); Assert.IsType(exception.InnerException); Assert.Null(exception.InnerException.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal( + $"Error reading '' at line 1 column 20 : Imports contains an invalid framework: '{expectedImport}' in 'project.json'.", + exception.Message); + Assert.Equal(1, exception.Line); + Assert.Equal(20, exception.Column); + } + else + { + Assert.Equal( + $"Error reading '' : Imports contains an invalid framework: '{expectedImport}' in 'project.json'.", + exception.Message); + } } - [Fact] - public void GetPackageSpec_WhenFrameworksImportsValueIsString_ReturnsImport() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueIsString_ReturnsImport(IEnvironmentVariableReader environmentVariableReader) { NuGetFramework expectedResult = NuGetFramework.Parse("net48"); var json = $"{{\"frameworks\":{{\"a\":{{\"imports\":\"{expectedResult.GetShortFolderName()}\"}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Collection( framework.Imports, actualResult => Assert.Equal(expectedResult, actualResult)); } - [Fact] - public void GetPackageSpec_WhenFrameworksImportsValueIsArrayOfStrings_ReturnsImports() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksImportsValueIsArrayOfStrings_ReturnsImports(IEnvironmentVariableReader environmentVariableReader) { NuGetFramework[] expectedResults = { NuGetFramework.Parse("net472"), NuGetFramework.Parse("net48") }; var json = $"{{\"frameworks\":{{\"a\":{{\"imports\":[\"{expectedResults[0].GetShortFolderName()}\",\"{expectedResults[1].GetShortFolderName()}\"]}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Collection( framework.Imports, @@ -2344,68 +2619,72 @@ public void GetPackageSpec_WhenFrameworksImportsValueIsArrayOfStrings_ReturnsImp actualResult => Assert.Equal(expectedResults[1], actualResult)); } - [Fact] - public void GetPackageSpec_WhenFrameworksRuntimeIdentifierGraphPathPropertyIsAbsent_ReturnsRuntimeIdentifierGraphPath() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksRuntimeIdentifierGraphPathPropertyIsAbsent_ReturnsRuntimeIdentifierGraphPath(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Null(framework.RuntimeIdentifierGraphPath); } [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("b")] - public void GetPackageSpec_WhenFrameworksRuntimeIdentifierGraphPathValueIsString_ReturnsRuntimeIdentifierGraphPath(string expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksRuntimeIdentifierGraphPathValueIsString_ReturnsRuntimeIdentifierGraphPath(IEnvironmentVariableReader environmentVariableReader, string expectedResult) { string runtimeIdentifierGraphPath = expectedResult == null ? "null" : $"\"{expectedResult}\""; var json = $"{{\"frameworks\":{{\"a\":{{\"runtimeIdentifierGraphPath\":{runtimeIdentifierGraphPath}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Equal(expectedResult, framework.RuntimeIdentifierGraphPath); } - [Fact] - public void GetPackageSpec_WhenFrameworksWarnPropertyIsAbsent_ReturnsWarn() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksWarnPropertyIsAbsent_ReturnsWarn(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"frameworks\":{\"a\":{}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.False(framework.Warn); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void GetPackageSpec_WhenFrameworksWarnValueIsValid_ReturnsWarn(bool expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFrameworksWarnValueIsValid_ReturnsWarn(IEnvironmentVariableReader environmentVariableReader, bool expectedResult) { var json = $"{{\"frameworks\":{{\"a\":{{\"warn\":{expectedResult.ToString().ToLowerInvariant()}}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); Assert.Equal(expectedResult, framework.Warn); } #pragma warning disable CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenPackIncludePropertyIsAbsent_ReturnsEmptyPackInclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackIncludePropertyIsAbsent_ReturnsEmptyPackInclude(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}"); + PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); Assert.Empty(packageSpec.PackInclude); } - [Fact] - public void GetPackageSpec_WhenPackIncludePropertyIsValid_ReturnsPackInclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackIncludePropertyIsValid_ReturnsPackInclude(IEnvironmentVariableReader environmentVariableReader) { var expectedResults = new List>() { new KeyValuePair("a", "b"), new KeyValuePair("c", "d") }; var json = $"{{\"packInclude\":{{\"{expectedResults[0].Key}\":\"{expectedResults[0].Value}\",\"{expectedResults[1].Key}\":\"{expectedResults[1].Value}\"}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.PackInclude, @@ -2414,11 +2693,11 @@ public void GetPackageSpec_WhenPackIncludePropertyIsValid_ReturnsPackInclude() } [Theory] - [InlineData("{}")] - [InlineData("{\"packOptions\":null}")] - public void GetPackageSpec_WhenPackOptionsPropertyIsAbsentOrValueIsNull_ReturnsPackOptions(string json) + [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "{\"packOptions\":null}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPropertyIsAbsentOrValueIsNull_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader, string json) { - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.NotNull(packageSpec.PackOptions); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); @@ -2435,23 +2714,25 @@ public void GetPackageSpec_WhenPackOptionsPropertyIsAbsentOrValueIsNull_ReturnsP Assert.Empty(packageSpec.Tags); } - [Fact] - public void GetPackageSpec_WhenPackOptionsPropertyIsAbsent_OwnersAndTagsAreEmpty() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPropertyIsAbsent_OwnersAndTagsAreEmpty(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"owners\":[\"a\"],\"tags\":[\"b\"]}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.Owners); Assert.Empty(packageSpec.Tags); } - [Fact] - public void GetPackageSpec_WhenPackOptionsPropertyIsEmptyObject_ReturnsPackOptions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPropertyIsEmptyObject_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader) { string json = "{\"packOptions\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.NotNull(packageSpec.PackOptions); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); @@ -2468,8 +2749,9 @@ public void GetPackageSpec_WhenPackOptionsPropertyIsEmptyObject_ReturnsPackOptio Assert.Empty(packageSpec.Tags); } - [Fact] - public void GetPackageSpec_WhenPackOptionsValueIsValid_ReturnsPackOptions() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsValueIsValid_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader) { const string iconUrl = "a"; const string licenseUrl = "b"; @@ -2484,7 +2766,7 @@ public void GetPackageSpec_WhenPackOptionsValueIsValid_ReturnsPackOptions() $"\"projectUrl\":\"{projectUrl}\",\"releaseNotes\":\"{releaseNotes}\",\"requireLicenseAcceptance\":{requireLicenseAcceptance.ToString().ToLowerInvariant()}," + $"\"summary\":\"{summary}\",\"tags\":[{string.Join(",", tags.Select(tag => $"\"{tag}\""))}]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.NotNull(packageSpec.PackOptions); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); @@ -2500,612 +2782,610 @@ public void GetPackageSpec_WhenPackOptionsValueIsValid_ReturnsPackOptions() Assert.Equal(tags, packageSpec.Tags); } - [Fact] - public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsNull_ReturnsEmptyPackageTypes() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsNull_ReturnsEmptyPackageTypes(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"packageType\":null}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.PackOptions.PackageType); } [Theory] - [InlineData("true", 34)] - [InlineData("-2", 32)] - [InlineData("3.14", 34)] - [InlineData("{}", 31)] - [InlineData("[true]", 31)] - [InlineData("[-2]", 31)] - [InlineData("[3.14]", 31)] - [InlineData("[null]", 31)] - [InlineData("[{}]", 31)] - [InlineData("[[]]", 31)] - public void GetPackageSpec_WhenPackOptionsPackageTypeIsInvalid_Throws(string value, int expectedColumn) + [MemberData(nameof(TestEnvironmentVariableReader), "true", 34, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "-2", 32, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "3.14", 34, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "{}", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[true]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[-2]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[3.14]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[null]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[{}]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[[]]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPackageTypeIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader, string value, int expectedColumn) { var json = $"{{\"packOptions\":{{\"packageType\":{value}}}}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - Assert.Equal("The pack options package type must be a string or array of strings in 'project.json'.", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(expectedColumn, exception.Column); Assert.Null(exception.InnerException); + Assert.Equal("The pack options package type must be a string or array of strings in 'project.json'.", exception.Message); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(1, exception.Line); + Assert.Equal(expectedColumn, exception.Column); + } } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("\"a,b\"", "a,b")] - [InlineData("[\"a\"]", "a")] - [InlineData("[\"a b\"]", "a b")] - public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsValid_ReturnsPackageTypes(string value, string expectedName) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a,b\"", "a,b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a b\"]", "a b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsValid_ReturnsPackageTypes(IEnvironmentVariableReader environmentVariableReader, string value, string expectedName) { var expectedResult = new PackageType(expectedName, PackageType.EmptyVersion); var json = $"{{\"packOptions\":{{\"packageType\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.PackOptions.PackageType, actualResult => Assert.Equal(expectedResult, actualResult)); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesValueIsNull_ReturnsNullInclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesValueIsNull_ReturnsNullInclude(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":null}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesValueIsEmptyObject_ReturnsNullInclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesValueIsEmptyObject_ReturnsNullInclude(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsNull_ReturnsNullIncludeExcludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"include\":null}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsEmptyArray_ReturnsEmptyInclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsEmptyArray_ReturnsEmptyInclude(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"include\":[]}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.Include); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("\"a, b\"", "a, b")] - [InlineData("[null]", null)] - [InlineData("[\"\"]", "")] - [InlineData("[\"a\"]", "a")] - [InlineData("[\"a, b\"]", "a, b")] - [InlineData("[\"a\", \"b\"]", "a", "b")] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsValid_ReturnsInclude(string value, params string[] expectedResults) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsValid_ReturnsInclude(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) { expectedResults = expectedResults ?? new string[] { null }; var json = $"{{\"packOptions\":{{\"files\":{{\"include\":{value}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.Include); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"includeFiles\":null}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsEmptyArray_ReturnsEmptyIncludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsEmptyArray_ReturnsEmptyIncludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"includeFiles\":[]}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.IncludeFiles); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("\"a, b\"", "a, b")] - [InlineData("[null]", null)] - [InlineData("[\"\"]", "")] - [InlineData("[\"a\"]", "a")] - [InlineData("[\"a, b\"]", "a, b")] - [InlineData("[\"a\", \"b\"]", "a", "b")] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsValid_ReturnsIncludeFiles(string value, params string[] expectedResults) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsValid_ReturnsIncludeFiles(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) { expectedResults = expectedResults ?? new string[] { null }; var json = $"{{\"packOptions\":{{\"files\":{{\"includeFiles\":{value}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.IncludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsNull_ReturnsNullIncludeExcludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"exclude\":null}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsEmptyArray_ReturnsEmptyExclude() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsEmptyArray_ReturnsEmptyExclude(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"exclude\":[]}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.Exclude); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("\"a, b\"", "a, b")] - [InlineData("[null]", null)] - [InlineData("[\"\"]", "")] - [InlineData("[\"a\"]", "a")] - [InlineData("[\"a, b\"]", "a, b")] - [InlineData("[\"a\", \"b\"]", "a", "b")] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsValid_ReturnsExclude(string value, params string[] expectedResults) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsValid_ReturnsExclude(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) { expectedResults = expectedResults ?? new string[] { null }; var json = $"{{\"packOptions\":{{\"files\":{{\"exclude\":{value}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.Exclude); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"excludeFiles\":null}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsEmptyArray_ReturnsEmptyExcludeFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsEmptyArray_ReturnsEmptyExcludeFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"excludeFiles\":[]}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.ExcludeFiles); } [Theory] - [InlineData("\"a\"", "a")] - [InlineData("\"a, b\"", "a, b")] - [InlineData("[null]", null)] - [InlineData("[\"\"]", "")] - [InlineData("[\"a\"]", "a")] - [InlineData("[\"a, b\"]", "a, b")] - [InlineData("[\"a\", \"b\"]", "a", "b")] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsValid_ReturnsExcludeFiles(string value, params string[] expectedResults) + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsValid_ReturnsExcludeFiles(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) { expectedResults = expectedResults ?? new string[] { null }; var json = $"{{\"packOptions\":{{\"files\":{{\"excludeFiles\":{value}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.ExcludeFiles); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesMappingsPropertyIsAbsent_ReturnsNullMappings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesMappingsPropertyIsAbsent_ReturnsNullMappings(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.Mappings); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsNull_ReturnsNullMappings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsNull_ReturnsNullMappings(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"packOptions\":{\"files\":{\"mappings\":null}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.PackOptions.Mappings); } [Theory] - [InlineData("\"b\"", "b")] - [InlineData("\"b,c\"", "b,c")] - [InlineData("[\"b\", \"c\"]", "b", "c")] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsValid_ReturnsMappings(string value, params string[] expectedIncludes) + [MemberData(nameof(TestEnvironmentVariableReader), "\"b\"", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"b,c\"", "b,c", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "[\"b\", \"c\"]", "b", "c", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsValid_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedIncludes) { var expectedResults = new Dictionary() - { - { "a", new IncludeExcludeFiles() { Include = expectedIncludes } } - }; + { + { "a", new IncludeExcludeFiles() { Include = expectedIncludes } } + }; var json = $"{{\"packOptions\":{{\"files\":{{\"mappings\":{{\"a\":{value}}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasMultipleMappings_ReturnsMappings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasMultipleMappings_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader) { var expectedResults = new Dictionary() - { - { "a", new IncludeExcludeFiles() { Include = new[] { "b" } } }, - { "c", new IncludeExcludeFiles() { Include = new[] { "d", "e" } } } - }; + { + { "a", new IncludeExcludeFiles() { Include = new[] { "b" } } }, + { "c", new IncludeExcludeFiles() { Include = new[] { "d", "e" } } } + }; const string json = "{\"packOptions\":{\"files\":{\"mappings\":{\"a\":\"b\",\"c\":[\"d\", \"e\"]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); } - [Fact] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasFiles_ReturnsMappings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasFiles_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader) { var expectedResults = new Dictionary() - { - { - "a", - new IncludeExcludeFiles() { - Include = new [] { "b" }, - IncludeFiles = new [] { "c" }, - Exclude = new [] { "d" }, - ExcludeFiles = new [] { "e" } - } - } - }; + { + "a", + new IncludeExcludeFiles() + { + Include = new [] { "b" }, + IncludeFiles = new [] { "c" }, + Exclude = new [] { "d" }, + ExcludeFiles = new [] { "e" } + } + } + }; const string json = "{\"packOptions\":{\"files\":{\"mappings\":{\"a\":{\"include\":\"b\",\"includeFiles\":\"c\",\"exclude\":\"d\",\"excludeFiles\":\"e\"}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); } #pragma warning restore CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenRestorePropertyIsAbsent_ReturnsNullRestoreMetadata() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestorePropertyIsAbsent_ReturnsNullRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) { const string json = "{}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Null(packageSpec.RestoreMetadata); } - [Fact] - public void GetPackageSpec_WhenRestoreValueIsEmptyObject_ReturnsRestoreMetadata() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreValueIsEmptyObject_ReturnsRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.NotNull(packageSpec.RestoreMetadata); } [Theory] - [InlineData("null")] - [InlineData("\"\"")] - [InlineData("\"a\"")] - public void GetPackageSpec_WhenRestoreProjectStyleValueIsInvalid_ReturnsProjectStyle(string value) + [MemberData(nameof(TestEnvironmentVariableReader), "null", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreProjectStyleValueIsInvalid_ReturnsProjectStyle(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"restore\":{{\"projectStyle\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(ProjectStyle.Unknown, packageSpec.RestoreMetadata.ProjectStyle); } - [Fact] - public void GetPackageSpec_WhenRestoreProjectStyleValueIsValid_ReturnsProjectStyle() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreProjectStyleValueIsValid_ReturnsProjectStyle(IEnvironmentVariableReader environmentVariableReader) { const ProjectStyle expectedResult = ProjectStyle.PackageReference; var json = $"{{\"restore\":{{\"projectStyle\":\"{expectedResult.ToString().ToLowerInvariant()}\"}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreMetadata.ProjectStyle); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestoreProjectUniqueNameValueIsValid_ReturnsProjectUniqueName( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"projectUniqueName\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.ProjectUniqueName); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestoreOutputPathValueIsValid_ReturnsOutputPath( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"outputPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.OutputPath); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestorePackagesPathValueIsValid_ReturnsPackagesPath( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"packagesPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.PackagesPath); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestoreProjectJsonPathValueIsValid_ReturnsProjectJsonPath( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"projectJsonPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.ProjectJsonPath); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestoreProjectNameValueIsValid_ReturnsProjectName( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"projectName\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.ProjectName); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestoreProjectPathValueIsValid_ReturnsProjectPath( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"projectPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.ProjectPath); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] + [MemberData(nameof(TestEnvironmentVariableReader), null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), true, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenCrossTargetingValueIsValid_ReturnsCrossTargeting( + IEnvironmentVariableReader environmentVariableReader, bool? value, bool expectedValue) { var json = $"{{\"restore\":{{\"crossTargeting\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CrossTargeting); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] + [MemberData(nameof(TestEnvironmentVariableReader), null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), true, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenLegacyPackagesDirectoryValueIsValid_ReturnsLegacyPackagesDirectory( + IEnvironmentVariableReader environmentVariableReader, bool? value, bool expectedValue) { var json = $"{{\"restore\":{{\"legacyPackagesDirectory\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.LegacyPackagesDirectory); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] + [MemberData(nameof(TestEnvironmentVariableReader), null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), true, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenValidateRuntimeAssetsValueIsValid_ReturnsValidateRuntimeAssets( + IEnvironmentVariableReader environmentVariableReader, bool? value, bool expectedValue) { var json = $"{{\"restore\":{{\"validateRuntimeAssets\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.ValidateRuntimeAssets); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] + [MemberData(nameof(TestEnvironmentVariableReader), null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), true, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenSkipContentFileWriteValueIsValid_ReturnsSkipContentFileWrite( + IEnvironmentVariableReader environmentVariableReader, bool? value, bool expectedValue) { var json = $"{{\"restore\":{{\"skipContentFileWrite\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.SkipContentFileWrite); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] + [MemberData(nameof(TestEnvironmentVariableReader), null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), true, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), false, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenCentralPackageVersionsManagementEnabledValueIsValid_ReturnsCentralPackageVersionsManagementEnabled( + IEnvironmentVariableReader environmentVariableReader, bool? value, bool expectedValue) { var json = $"{{\"restore\":{{\"centralPackageVersionsManagementEnabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageVersionsEnabled); } [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] - public void GetPackageSpec_WhenCentralPackageFloatingVersionsEnabledValueIsValid_ReturnsCentralPackageFloatingVersionsEnabled( - bool? value, - bool expectedValue) - { - var json = $"{{\"restore\":{{\"centralPackageFloatingVersionsEnabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); - - Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageFloatingVersionsEnabled); - } - - [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] - public void GetPackageSpec_WhenCentralPackageVersionOverrideDisabledValueIsValid_ReturnsCentralPackageVersionOverrideDisabled( - bool? value, - bool expectedValue) - { - var json = $"{{\"restore\":{{\"centralPackageVersionOverrideDisabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); - - Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageVersionOverrideDisabled); - } - - [Theory] - [InlineData(null, false)] - [InlineData(true, true)] - [InlineData(false, false)] - public void GetPackageSpec_WhenCentralPackageTransitivePinningEnabledValueIsValid_ReturnsCentralPackageTransitivePinningEnabled( - bool? value, - bool expectedValue) - { - var json = $"{{\"restore\":{{\"CentralPackageTransitivePinningEnabled\":{(value.HasValue ? value.ToString().ToLowerInvariant() : "null")}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); - - Assert.Equal(expectedValue, packageSpec.RestoreMetadata.CentralPackageTransitivePinningEnabled); - } - - [Fact] - public void GetPackageSpec_WhenSourcesValueIsEmptyObject_ReturnsEmptySources() + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenSourcesValueIsEmptyObject_ReturnsEmptySources(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"sources\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.Sources); } - [Fact] - public void GetPackageSpec_WhenSourcesValueIsValid_ReturnsSources() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenSourcesValueIsValid_ReturnsSources(IEnvironmentVariableReader environmentVariableReader) { PackageSource[] expectedResults = { new PackageSource(source: "a"), new PackageSource(source: "b") }; string values = string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult.Name}\":{{}}")); var json = $"{{\"restore\":{{\"sources\":{{{values}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.RestoreMetadata.Sources); } - [Fact] - public void GetPackageSpec_WhenFilesValueIsEmptyObject_ReturnsEmptyFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFilesValueIsEmptyObject_ReturnsEmptyFiles(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"files\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.Files); } - [Fact] - public void GetPackageSpec_WhenFilesValueIsValid_ReturnsFiles() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFilesValueIsValid_ReturnsFiles(IEnvironmentVariableReader environmentVariableReader) { ProjectRestoreMetadataFile[] expectedResults = { - new ProjectRestoreMetadataFile(packagePath: "a", absolutePath: "b"), - new ProjectRestoreMetadataFile(packagePath: "c", absolutePath:"d") - }; + new ProjectRestoreMetadataFile(packagePath: "a", absolutePath: "b"), + new ProjectRestoreMetadataFile(packagePath: "c", absolutePath:"d") + }; string values = string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult.PackagePath}\":\"{expectedResult.AbsolutePath}\"")); var json = $"{{\"restore\":{{\"files\":{{{values}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.RestoreMetadata.Files); } - [Fact] - public void GetPackageSpec_WhenRestoreFrameworksValueIsEmptyObject_ReturnsEmptyFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFrameworksValueIsEmptyObject_ReturnsEmptyFrameworks(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"frameworks\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.TargetFrameworks); } - [Fact] - public void GetPackageSpec_WhenRestoreFrameworksFrameworkNameValueIsValid_ReturnsFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFrameworksFrameworkNameValueIsValid_ReturnsFrameworks(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new ProjectRestoreMetadataFrameworkInfo(NuGetFramework.ParseFolder("net472")); var json = $"{{\"restore\":{{\"frameworks\":{{\"{expectedResult.FrameworkName.GetShortFolderName()}\":{{}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.RestoreMetadata.TargetFrameworks, actualResult => Assert.Equal(expectedResult, actualResult)); } - [Fact] - public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenceWithoutAssets_ReturnsFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenceWithoutAssets_ReturnsFrameworks(IEnvironmentVariableReader environmentVariableReader) { var projectReference = new ProjectRestoreReference() { @@ -3118,15 +3398,16 @@ public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenc var json = $"{{\"restore\":{{\"frameworks\":{{\"{expectedResult.FrameworkName.GetShortFolderName()}\":{{\"projectReferences\":{{" + $"\"{projectReference.ProjectUniqueName}\":{{\"projectPath\":\"{projectReference.ProjectPath}\"}}}}}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.RestoreMetadata.TargetFrameworks, actualResult => Assert.Equal(expectedResult, actualResult)); } - [Fact] - public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenceWithAssets_ReturnsFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenceWithAssets_ReturnsFrameworks(IEnvironmentVariableReader environmentVariableReader) { var projectReference = new ProjectRestoreReference() { @@ -3144,85 +3425,93 @@ public void GetPackageSpec_WhenRestoreFrameworksFrameworkValueHasProjectReferenc $"\"{projectReference.ProjectUniqueName}\":{{\"projectPath\":\"{projectReference.ProjectPath}\"," + $"\"includeAssets\":\"{projectReference.IncludeAssets}\",\"excludeAssets\":\"{projectReference.ExcludeAssets}\"," + $"\"privateAssets\":\"{projectReference.PrivateAssets}\"}}}}}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.RestoreMetadata.TargetFrameworks, actualResult => Assert.Equal(expectedResult, actualResult)); } - [Fact] - public void GetPackageSpec_WhenRestoreConfigFilePathsValueIsEmptyArray_ReturnsEmptyConfigFilePaths() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreConfigFilePathsValueIsEmptyArray_ReturnsEmptyConfigFilePaths(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"configFilePaths\":[]}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.ConfigFilePaths); } - [Fact] - public void GetPackageSpec_WhenRestoreConfigFilePathsValueIsValid_ReturnsConfigFilePaths() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreConfigFilePathsValueIsValid_ReturnsConfigFilePaths(IEnvironmentVariableReader environmentVariableReader) { string[] expectedResults = { "a", "b" }; string values = string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult}\"")); var json = $"{{\"restore\":{{\"configFilePaths\":[{values}]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.RestoreMetadata.ConfigFilePaths); } - [Fact] - public void GetPackageSpec_WhenRestoreFallbackFoldersValueIsEmptyArray_ReturnsEmptyFallbackFolders() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFallbackFoldersValueIsEmptyArray_ReturnsEmptyFallbackFolders(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"fallbackFolders\":[]}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.FallbackFolders); } - [Fact] - public void GetPackageSpec_WhenRestoreFallbackFoldersValueIsValid_ReturnsConfigFilePaths() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreFallbackFoldersValueIsValid_ReturnsConfigFilePaths(IEnvironmentVariableReader environmentVariableReader) { string[] expectedResults = { "a", "b" }; string values = string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult}\"")); var json = $"{{\"restore\":{{\"fallbackFolders\":[{values}]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.RestoreMetadata.FallbackFolders); } - [Fact] - public void GetPackageSpec_WhenRestoreOriginalTargetFrameworksValueIsEmptyArray_ReturnsEmptyOriginalTargetFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreOriginalTargetFrameworksValueIsEmptyArray_ReturnsEmptyOriginalTargetFrameworks(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"restore\":{\"originalTargetFrameworks\":[]}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.RestoreMetadata.OriginalTargetFrameworks); } - [Fact] - public void GetPackageSpec_WhenRestoreOriginalTargetFrameworksValueIsValid_ReturnsOriginalTargetFrameworks() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreOriginalTargetFrameworksValueIsValid_ReturnsOriginalTargetFrameworks(IEnvironmentVariableReader environmentVariableReader) { string[] expectedResults = { "a", "b" }; string values = string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult}\"")); var json = $"{{\"restore\":{{\"originalTargetFrameworks\":[{values}]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResults, packageSpec.RestoreMetadata.OriginalTargetFrameworks); } - [Fact] - public void GetPackageSpec_WhenRestoreWarningPropertiesValueIsEmptyObject_ReturnsWarningProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreWarningPropertiesValueIsEmptyObject_ReturnsWarningProperties(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new WarningProperties(); const string json = "{\"restore\":{\"warningProperties\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreMetadata.ProjectWideWarningProperties); } - [Fact] - public void GetPackageSpec_WhenRestoreWarningPropertiesValueIsValid_ReturnsWarningProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreWarningPropertiesValueIsValid_ReturnsWarningProperties(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new WarningProperties( new HashSet() { NuGetLogCode.NU3000 }, @@ -3231,23 +3520,25 @@ public void GetPackageSpec_WhenRestoreWarningPropertiesValueIsValid_ReturnsWarni new HashSet()); var json = $"{{\"restore\":{{\"warningProperties\":{{\"allWarningsAsErrors\":{expectedResult.AllWarningsAsErrors.ToString().ToLowerInvariant()}," + $"\"warnAsError\":[\"{expectedResult.WarningsAsErrors.Single()}\"],\"noWarn\":[\"{expectedResult.NoWarn.Single()}\"]}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreMetadata.ProjectWideWarningProperties); } - [Fact] - public void GetPackageSpec_WhenRestoreRestoreLockPropertiesValueIsEmptyObject_ReturnsRestoreLockProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreRestoreLockPropertiesValueIsEmptyObject_ReturnsRestoreLockProperties(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new RestoreLockProperties(); const string json = "{\"restore\":{\"restoreLockProperties\":{}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreMetadata.RestoreLockProperties); } - [Fact] - public void GetPackageSpec_WhenRestoreRestoreLockPropertiesValueIsValid_ReturnsRestoreLockProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreRestoreLockPropertiesValueIsValid_ReturnsRestoreLockProperties(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new RestoreLockProperties( restorePackagesWithLockFile: "a", @@ -3256,61 +3547,64 @@ public void GetPackageSpec_WhenRestoreRestoreLockPropertiesValueIsValid_ReturnsR var json = $"{{\"restore\":{{\"restoreLockProperties\":{{\"restoreLockedMode\":{expectedResult.RestoreLockedMode.ToString().ToLowerInvariant()}," + $"\"restorePackagesWithLockFile\":\"{expectedResult.RestorePackagesWithLockFile}\"," + $"\"nuGetLockFilePath\":\"{expectedResult.NuGetLockFilePath}\"}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreMetadata.RestoreLockProperties); } [Theory] - [InlineData("null")] - [InlineData("\"\"")] - [InlineData("\"a\"")] - public void GetPackageSpec_WhenRestorePackagesConfigPathValueIsValidAndProjectStyleValueIsNotPackagesConfig_DoesNotReturnPackagesConfigPath( - string value) + [MemberData(nameof(TestEnvironmentVariableReader), "null", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestorePackagesConfigPathValueIsValidAndProjectStyleValueIsNotPackagesConfig_DoesNotReturnPackagesConfigPath(IEnvironmentVariableReader environmentVariableReader, string value) { var json = $"{{\"restore\":{{\"projectStyle\":\"PackageReference\",\"packagesConfigPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.IsNotType(packageSpec.RestoreMetadata); } [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenRestorePackagesConfigPathValueIsValidAndProjectStyleValueIsPackagesConfig_ReturnsPackagesConfigPath( + IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) { var json = $"{{\"restore\":{{\"projectStyle\":\"PackagesConfig\",\"packagesConfigPath\":{value}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.IsType(packageSpec.RestoreMetadata); Assert.Equal(expectedValue, ((PackagesConfigProjectRestoreMetadata)packageSpec.RestoreMetadata).PackagesConfigPath); } - [Fact] - public void GetPackageSpec_WhenRestoreSettingsValueIsEmptyObject_ReturnsRestoreSettings() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRestoreSettingsValueIsEmptyObject_ReturnsRestoreSettings(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = new ProjectRestoreSettings(); const string json = "{\"restoreSettings\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RestoreSettings); } - [Fact] - public void GetPackageSpec_WhenRuntimesValueIsEmptyObject_ReturnsRuntimes() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRuntimesValueIsEmptyObject_ReturnsRuntimes(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = RuntimeGraph.Empty; const string json = "{\"runtimes\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenRuntimesValueIsValidWithImports_ReturnsRuntimes() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRuntimesValueIsValidWithImports_ReturnsRuntimes(IEnvironmentVariableReader environmentVariableReader) { var runtimeDescription = new RuntimeDescription( runtimeIdentifier: "a", @@ -3319,13 +3613,14 @@ public void GetPackageSpec_WhenRuntimesValueIsValidWithImports_ReturnsRuntimes() var expectedResult = new RuntimeGraph(new[] { runtimeDescription }); var json = $"{{\"runtimes\":{{\"{runtimeDescription.RuntimeIdentifier}\":{{\"#import\":[" + $"{string.Join(",", runtimeDescription.InheritedRuntimes.Select(runtime => $"\"{runtime}\""))}]}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySet_ReturnsRuntimes() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySet_ReturnsRuntimes(IEnvironmentVariableReader environmentVariableReader) { var dependencySet = new RuntimeDependencySet(id: "b"); var runtimeDescription = new RuntimeDescription( @@ -3334,13 +3629,14 @@ public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySet_ReturnsRunt runtimeDependencySets: new[] { dependencySet }); var expectedResult = new RuntimeGraph(new[] { runtimeDescription }); var json = $"{{\"runtimes\":{{\"{runtimeDescription.RuntimeIdentifier}\":{{\"{dependencySet.Id}\":{{}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySetWithDependency_ReturnsRuntimes() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySetWithDependency_ReturnsRuntimes(IEnvironmentVariableReader environmentVariableReader) { var dependency = new RuntimePackageDependency("c", VersionRange.Parse("[1.2.3,4.5.6)")); var dependencySet = new RuntimeDependencySet(id: "b", new[] { dependency }); @@ -3351,75 +3647,85 @@ public void GetPackageSpec_WhenRuntimesValueIsValidWithDependencySetWithDependen var expectedResult = new RuntimeGraph(new[] { runtimeDescription }); var json = $"{{\"runtimes\":{{\"{runtimeDescription.RuntimeIdentifier}\":{{\"{dependencySet.Id}\":{{" + $"\"{dependency.Id}\":\"{dependency.VersionRange.ToLegacyString()}\"}}}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenSupportsValueIsEmptyObject_ReturnsSupports() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenSupportsValueIsEmptyObject_ReturnsSupports(IEnvironmentVariableReader environmentVariableReader) { var expectedResult = RuntimeGraph.Empty; const string json = "{\"supports\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenSupportsValueIsValidWithCompatibilityProfiles_ReturnsSupports() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenSupportsValueIsValidWithCompatibilityProfiles_ReturnsSupports(IEnvironmentVariableReader environmentVariableReader) { var profile = new CompatibilityProfile(name: "a"); var expectedResult = new RuntimeGraph(new[] { profile }); var json = $"{{\"supports\":{{\"{profile.Name}\":{{}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } - [Fact] - public void GetPackageSpec_WhenSupportsValueIsValidWithCompatibilityProfilesAndFrameworkRuntimePairs_ReturnsSupports() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenSupportsValueIsValidWithCompatibilityProfilesAndFrameworkRuntimePairs_ReturnsSupports(IEnvironmentVariableReader environmentVariableReader) { FrameworkRuntimePair[] restoreContexts = new[] { - new FrameworkRuntimePair(NuGetFramework.Parse("net472"), "b"), - new FrameworkRuntimePair(NuGetFramework.Parse("net48"), "c") - }; + new FrameworkRuntimePair(NuGetFramework.Parse("net472"), "b"), + new FrameworkRuntimePair(NuGetFramework.Parse("net48"), "c") + }; var profile = new CompatibilityProfile(name: "a", restoreContexts); var expectedResult = new RuntimeGraph(new[] { profile }); var json = $"{{\"supports\":{{\"{profile.Name}\":{{" + $"\"{restoreContexts[0].Framework.GetShortFolderName()}\":\"{restoreContexts[0].RuntimeIdentifier}\"," + $"\"{restoreContexts[1].Framework.GetShortFolderName()}\":[\"{restoreContexts[1].RuntimeIdentifier}\"]}}}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } #pragma warning disable CS0612 // Type or member is obsolete - [Fact] - public void GetPackageSpec_WhenScriptsValueIsEmptyObject_ReturnsScripts() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenScriptsValueIsEmptyObject_ReturnsScripts(IEnvironmentVariableReader environmentVariableReader) { const string json = "{\"scripts\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Empty(packageSpec.Scripts); } - [Fact] - public void GetPackageSpec_WhenScriptsValueIsInvalid_Throws() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenScriptsValueIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader) { var json = "{\"scripts\":{\"a\":0}}"; - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json)); + FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); Assert.Equal("The value of a script in 'project.json' can only be a string or an array of strings", exception.Message); - Assert.Equal(1, exception.Line); - Assert.Equal(17, exception.Column); Assert.Null(exception.InnerException); + + if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) + { + Assert.Equal(1, exception.Line); + Assert.Equal(17, exception.Column); + } } - [Fact] - public void GetPackageSpec_WhenScriptsValueIsValid_ReturnsScripts() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenScriptsValueIsValid_ReturnsScripts(IEnvironmentVariableReader environmentVariableReader) { const string name0 = "a"; const string name1 = "b"; @@ -3428,7 +3734,7 @@ public void GetPackageSpec_WhenScriptsValueIsValid_ReturnsScripts() const string script2 = "e"; var json = $"{{\"scripts\":{{\"{name0}\":\"{script0}\",\"{name1}\":[\"{script1}\",\"{script2}\"]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Collection( packageSpec.Scripts, @@ -3451,76 +3757,79 @@ public void GetPackageSpec_WhenScriptsValueIsValid_ReturnsScripts() #pragma warning restore CS0612 // Type or member is obsolete [Theory] - [InlineData("null", null)] - [InlineData("\"\"", "")] - [InlineData("\"a\"", "a")] - public void GetPackageSpec_WhenTitleValueIsValid_ReturnsTitle(string value, string expectedResult) + [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenTitleValueIsValid_ReturnsTitle(IEnvironmentVariableReader environmentVariableReader, string value, string expectedResult) { var json = $"{{\"title\":{value}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.Title); } - [Fact] - public void GetPackageSpec_WhenNameIsNull_RestoreMetadataProvidesFallbackName() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenNameIsNull_RestoreMetadataProvidesFallbackName(IEnvironmentVariableReader environmentVariableReader) { const string expectedResult = "a"; var json = $"{{\"restore\":{{\"projectName\":\"{expectedResult}\"}}}}"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.Name); } [Theory] - [InlineData("{\"restore\":{\"projectJsonPath\":\"a\"}}")] - [InlineData("{\"restore\":{\"projectPath\":\"a\"}}")] - [InlineData("{\"restore\":{\"projectJsonPath\":\"a\",\"projectPath\":\"b\"}}")] - public void GetPackageSpec_WhenFilePathIsNull_RestoreMetadataProvidesFallbackFilePath(string json) + [MemberData(nameof(TestEnvironmentVariableReader), "{\"restore\":{\"projectJsonPath\":\"a\"}}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "{\"restore\":{\"projectPath\":\"a\"}}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + [MemberData(nameof(TestEnvironmentVariableReader), "{\"restore\":{\"projectJsonPath\":\"a\",\"projectPath\":\"b\"}}", MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WhenFilePathIsNull_RestoreMetadataProvidesFallbackFilePath(IEnvironmentVariableReader environmentVariableReader, string json) { const string expectedResult = "a"; - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.Equal(expectedResult, packageSpec.FilePath); } - [Fact] - public void GetTargetFrameworkInformation_WithAnAlias() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetTargetFrameworkInformation_WithAnAlias(IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"net46\":{ \"targetAlias\" : \"alias\"}}}"); + TargetFrameworkInformation framework = GetFramework("{\"frameworks\":{\"net46\":{ \"targetAlias\" : \"alias\"}}}", environmentVariableReader); Assert.Equal("alias", framework.TargetAlias); } - [Fact] - public void PackageSpecReader_ReadsRestoreMetadataWithAliases() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_ReadsRestoreMetadataWithAliases(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""restore"": { - ""projectUniqueName"": ""projectUniqueName"", - ""projectName"": ""projectName"", - ""projectPath"": ""projectPath"", - ""projectJsonPath"": ""projectJsonPath"", - ""packagesPath"": ""packagesPath"", - ""outputPath"": ""outputPath"", - ""projectStyle"": ""PackageReference"", - ""crossTargeting"": true, - ""frameworks"": { - ""frameworkidentifier123-frameworkprofile"": { - ""targetAlias"" : ""alias"", - ""projectReferences"": {} - } - }, - ""warningProperties"": { - } - } -}"; + ""restore"": { + ""projectUniqueName"": ""projectUniqueName"", + ""projectName"": ""projectName"", + ""projectPath"": ""projectPath"", + ""projectJsonPath"": ""projectJsonPath"", + ""packagesPath"": ""packagesPath"", + ""outputPath"": ""outputPath"", + ""projectStyle"": ""PackageReference"", + ""crossTargeting"": true, + ""frameworks"": { + ""frameworkidentifier123-frameworkprofile"": { + ""targetAlias"" : ""alias"", + ""projectReferences"": {} + } + }, + ""warningProperties"": { + } + } + }"; - var actual = JsonPackageSpecReader.GetPackageSpec(json, "TestProject", "project.json"); + var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); // Assert var metadata = actual.RestoreMetadata; @@ -3530,50 +3839,79 @@ public void PackageSpecReader_ReadsRestoreMetadataWithAliases() Assert.Equal("alias", metadata.TargetFrameworks.Single().TargetAlias); } - - [Fact] - public void PackageSpecReader_Read() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_Read(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = @"{ - ""centralTransitiveDependencyGroups"": { - "".NETCoreApp,Version=v3.1"": { - ""Foo"": { - ""exclude"": ""Native"", - ""include"": ""Build"", - ""suppressParent"": ""All"", - ""version"": ""1.0.0"" - } - }, - "".NETCoreApp,Version=v3.0"": { - ""Bar"": { - ""exclude"": ""Native"", - ""include"": ""Build"", - ""suppressParent"": ""All"", - ""version"": ""2.0.0"" + ""centralTransitiveDependencyGroups"": { + "".NETCoreApp,Version=v3.1"": { + ""Foo"": { + ""exclude"": ""Native"", + ""include"": ""Build"", + ""suppressParent"": ""All"", + ""version"": ""1.0.0"" + } + }, + "".NETCoreApp,Version=v3.0"": { + ""Bar"": { + ""exclude"": ""Native"", + ""include"": ""Build"", + ""suppressParent"": ""All"", + ""version"": ""2.0.0"" + } + } } - } - } - }"; + }"; // Act var results = new List(); - using (var stringReader = new StringReader(json.ToString())) - using (var jsonReader = new JsonTextReader(stringReader)) + if (environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING).Equals(bool.FalseString, StringComparison.OrdinalIgnoreCase)) { - jsonReader.ReadObject(ctdPropertyName => + using Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var reader = new Utf8JsonStreamReader(stream); + + if (reader.TokenType == JsonTokenType.StartObject) { - jsonReader.ReadObject(frameworkPropertyName => + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) { - var dependencies = new List(); - NuGetFramework framework = NuGetFramework.Parse(frameworkPropertyName); - JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( - jsonReader: jsonReader, - results: dependencies, - packageSpecPath: "SomePath"); - results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + if (reader.Read() && reader.TokenType == JsonTokenType.StartObject) + { + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + var frameworkPropertyName = reader.GetString(); + NuGetFramework framework = NuGetFramework.Parse(frameworkPropertyName); + + JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( + jsonReader: ref reader, + results: out var dependencies, + packageSpecPath: "SomePath"); + results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + } + } + } + } + } + else + { + using (var stringReader = new StringReader(json.ToString())) + using (var jsonReader = new JsonTextReader(stringReader)) + { + jsonReader.ReadObject(ctdPropertyName => + { + jsonReader.ReadObject(frameworkPropertyName => + { + var dependencies = new List(); + NuGetFramework framework = NuGetFramework.Parse(frameworkPropertyName); + JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( + jsonReader: jsonReader, + results: dependencies, + packageSpecPath: "SomePath"); + results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + }); }); - }); + } } // Assert @@ -3594,24 +3932,80 @@ public void PackageSpecReader_Read() Assert.True(secondGroup.TransitiveDependencies.First().VersionCentrallyManaged); } - [Fact] - public void GetPackageSpec_WithSecondaryFrameworks_ReturnsTargetFrameworkInformationWithDualCompatibilityFramework() + + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void PackageSpecReader_Malformed_Exception(IEnvironmentVariableReader environmentVariableReader) + { + // Arrange + var json = @" +{ + "".NETCoreApp,Version=v3.1"": { + ""Foo"":"; + + // Act + var results = new List(); + if (environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING).Equals(bool.FalseString, StringComparison.OrdinalIgnoreCase)) + { + Assert.ThrowsAny(() => + { + using Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var reader = new Utf8JsonStreamReader(stream); + + if (reader.TokenType == JsonTokenType.StartObject) + { + reader.Read(); + NuGetFramework framework = NuGetFramework.Parse(reader.GetString()); + + JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( + jsonReader: ref reader, + results: out var dependencies, + packageSpecPath: "SomePath"); + results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + } + }); + } + else + { + using (var stringReader = new StringReader(json.ToString())) + using (var jsonReader = new JsonTextReader(stringReader)) + { + jsonReader.Read(); + jsonReader.Read(); + var dependencies = new List(); + NuGetFramework framework = NuGetFramework.Parse((string)jsonReader.Value); + JsonPackageSpecReader.ReadCentralTransitiveDependencyGroup( + jsonReader: jsonReader, + results: dependencies, + packageSpecPath: "SomePath"); + results.Add(new CentralTransitiveDependencyGroup(framework, dependencies)); + } + // Assert + Assert.Equal(1, results.Count); + var firstGroup = results.ElementAt(0); + } + } + + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WithSecondaryFrameworks_ReturnsTargetFrameworkInformationWithDualCompatibilityFramework(IEnvironmentVariableReader environmentVariableReader) { var json = $"{{\"frameworks\":{{\"net5.0\":{{\"secondaryFramework\": \"native\"}}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); framework.FrameworkName.Should().BeOfType(); var dualCompatibilityFramework = framework.FrameworkName as DualCompatibilityFramework; dualCompatibilityFramework.RootFramework.Should().Be(FrameworkConstants.CommonFrameworks.Net50); dualCompatibilityFramework.SecondaryFramework.Should().Be(FrameworkConstants.CommonFrameworks.Native); } - [Fact] - public void GetPackageSpec_WithAssetTargetFallbackAndWithSecondaryFrameworks_ReturnsTargetFrameworkInformationWithDualCompatibilityFramework() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WithAssetTargetFallbackAndWithSecondaryFrameworks_ReturnsTargetFrameworkInformationWithDualCompatibilityFramework(IEnvironmentVariableReader environmentVariableReader) { var json = $"{{\"frameworks\":{{\"net5.0\":{{\"assetTargetFallback\": true, \"imports\": [\"net472\", \"net471\"], \"secondaryFramework\": \"native\" }}}}}}"; - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); framework.FrameworkName.Should().BeOfType(); framework.AssetTargetFallback.Should().BeTrue(); var assetTargetFallbackFramework = framework.FrameworkName as AssetTargetFallbackFramework; @@ -3624,14 +4018,15 @@ public void GetPackageSpec_WithAssetTargetFallbackAndWithSecondaryFrameworks_Ret assetTargetFallbackFramework.Fallback.Last().Should().Be(FrameworkConstants.CommonFrameworks.Net471); } - [Fact] - public void GetPackageSpec_WithRestoreAuditProperties_ReturnsRestoreAuditProperties() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void GetPackageSpec_WithRestoreAuditProperties_ReturnsRestoreAuditProperties(IEnvironmentVariableReader environmentVariableReader) { // Arrange var json = $"{{\"restore\":{{\"restoreAuditProperties\":{{\"enableAudit\": \"a\", \"auditLevel\": \"b\", \"auditMode\": \"c\"}}}}}}"; // Act - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); // Assert packageSpec.RestoreMetadata.RestoreAuditProperties.EnableAudit.Should().Be("a"); @@ -3752,30 +4147,41 @@ private static PackageSpec GetPackageSpec(string json) } } - private static LibraryDependency GetDependency(string json) + private static PackageSpec GetPackageSpec(string json, IEnvironmentVariableReader environmentVariableReader) + { + return GetPackageSpec(json, name: null, packageSpecPath: null, snapshotValue: null, environmentVariableReader: environmentVariableReader); + } + + private static PackageSpec GetPackageSpec(string json, string name, string packageSpecPath, string snapshotValue, IEnvironmentVariableReader environmentVariableReader) + { + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + return JsonPackageSpecReader.GetPackageSpec(stream, name, packageSpecPath, snapshotValue, environmentVariableReader, true); + } + + private static LibraryDependency GetDependency(string json, IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); return packageSpec.Dependencies.Single(); } - private static TargetFrameworkInformation GetFramework(string json) + private static TargetFrameworkInformation GetFramework(string json, IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec(json); + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); return packageSpec.TargetFrameworks.Single(); } - private static LibraryDependency GetFrameworksDependency(string json) + private static LibraryDependency GetFrameworksDependency(string json, IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); return framework.Dependencies.Single(); } - private static FrameworkDependency GetFrameworksFrameworkReference(string json) + private static FrameworkDependency GetFrameworksFrameworkReference(string json, IEnvironmentVariableReader environmentVariableReader) { - TargetFrameworkInformation framework = GetFramework(json); + TargetFrameworkInformation framework = GetFramework(json, environmentVariableReader); return framework.FrameworkReferences.Single(); } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LazyStringSplitTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LazyStringSplitTests.cs new file mode 100644 index 00000000000..e314c4f7226 --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LazyStringSplitTests.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. + +using System.Collections.Generic; +using System; +using Xunit; + +namespace NuGet.ProjectModel.Test +{ + public sealed class LazyStringSplitTests + { + [Theory] + [InlineData("a;b;c", ';', new[] { "a", "b", "c" })] + [InlineData("a_b_c", '_', new[] { "a", "b", "c" })] + [InlineData("aa;bb;cc", ';', new[] { "aa", "bb", "cc" })] + [InlineData("aaa;bbb;ccc", ';', new[] { "aaa", "bbb", "ccc" })] + [InlineData(";a;b;c", ';', new[] { "a", "b", "c" })] + [InlineData("a;b;c;", ';', new[] { "a", "b", "c" })] + [InlineData(";a;b;c;", ';', new[] { "a", "b", "c" })] + [InlineData(";;a;;b;;c;;", ';', new[] { "a", "b", "c" })] + [InlineData("", ';', new string[0])] + [InlineData(";", ';', new string[0])] + [InlineData(";;", ';', new string[0])] + [InlineData(";;;", ';', new string[0])] + [InlineData(";;;a", ';', new[] { "a" })] + [InlineData("a;;;", ';', new[] { "a" })] + [InlineData(";a;;", ';', new[] { "a" })] + [InlineData(";;a;", ';', new[] { "a" })] + [InlineData("a", ';', new[] { "a" })] + [InlineData("aa", ';', new[] { "aa" })] + public void ProducesCorrectEnumeration(string input, char delimiter, string[] expected) + { + // This boxes + IEnumerable actual = new LazyStringSplit(input, delimiter); + + Assert.Equal(expected, actual); + + // Non boxing foreach + var list = new List(); + + foreach (var s in new LazyStringSplit(input, delimiter)) + { + list.Add(s); + } + + Assert.Equal(expected, list); + + // Equivalence with string.Split + Assert.Equal(expected, input.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries)); + } + + [Fact] + public void Constructor_WithNullInput_Throws() + { + Assert.Throws(() => new LazyStringSplit(null!, ' ')); + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs index 54977dc03b8..67a3b192a42 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Newtonsoft.Json.Linq; using NuGet.Common; using NuGet.Frameworks; @@ -19,8 +20,10 @@ namespace NuGet.ProjectModel.Test public class LockFileFormatTests { // Verify the value of locked has no impact on the parsed lock file - [Fact] - public void LockFileFormat_LockedPropertyIsIgnored() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + + public void LockFileFormat_LockedPropertyIsIgnored(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContentTrue = @"{ @@ -148,9 +151,11 @@ public void LockFileFormat_LockedPropertyIsIgnored() var lockFileFormat = new LockFileFormat(); // Act - var lockFileTrue = lockFileFormat.Parse(lockFileContentTrue, "In Memory"); - var lockFileFalse = lockFileFormat.Parse(lockFileContentFalse, "In Memory"); - var lockFileMissing = lockFileFormat.Parse(lockFileContentMissing, "In Memory"); +#pragma warning disable CS0612 // Type or member is obsolete + var lockFileTrue = Parse(lockFileContentTrue, "In Memory", environmentVariableReader); + var lockFileFalse = Parse(lockFileContentFalse, "In Memory", environmentVariableReader); + var lockFileMissing = Parse(lockFileContentMissing, "In Memory", environmentVariableReader); +#pragma warning restore CS0612 // Type or member is obsolete var lockFileTrueString = lockFileFormat.Render(lockFileTrue); var lockFileFalseString = lockFileFormat.Render(lockFileFalse); @@ -164,8 +169,9 @@ public void LockFileFormat_LockedPropertyIsIgnored() Assert.Equal(lockFileTrueString, lockFileMissingString); } - [Fact] - public void LockFileFormat_ReadsLockFileWithNoTools() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsLockFileWithNoTools(IEnvironmentVariableReader environmentVariableReader) { var lockFileContent = @"{ ""version"": 1, @@ -206,14 +212,12 @@ public void LockFileFormat_ReadsLockFileWithNoTools() "".NETPlatform,Version=v5.0"": [] } }"; - var lockFileFormat = new LockFileFormat(); - var lockFile = lockFileFormat.Parse(lockFileContent, "In Memory"); + var lockFile = Parse(lockFileContent, "In Memory", environmentVariableReader); Assert.Equal(1, lockFile.Version); var target = lockFile.Targets.Single(); Assert.Equal(NuGetFramework.Parse("dotnet"), target.TargetFramework); - var runtimeTargetLibrary = target.Libraries.Single(); Assert.Equal("System.Runtime", runtimeTargetLibrary.Name); Assert.Equal(NuGetVersion.Parse("4.0.20-beta-22927"), runtimeTargetLibrary.Version); @@ -1328,8 +1332,9 @@ public void LockFileFormat_WritesMinimalWarningMessageWithWarningLevel() Assert.Equal(expected, output); } - [Fact] - public void LockFileFormat_ReadsMinimalErrorMessage() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsMinimalErrorMessage(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1378,8 +1383,7 @@ public void LockFileFormat_ReadsMinimalErrorMessage() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1400,8 +1404,92 @@ public void LockFileFormat_ReadsMinimalErrorMessage() Assert.Equal("test log message", logMessage.Message); } - [Fact] - public void LockFileFormat_ReadsFullErrorMessage() + + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_SkipsInvalidErrorMessage(IEnvironmentVariableReader environmentVariableReader) + { + // Arrange + var lockFileContent = @"{ + ""version"": 3, + ""targets"": { + "".NETPlatform,Version=v5.0"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""type"": ""package"", + ""dependencies"": { + ""Frob"": ""4.0.20"" + }, + ""compile"": { + ""ref/dotnet/System.Runtime.dll"": {} + } + } + } + }, + ""libraries"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""sha512"": ""sup3rs3cur3"", + ""type"": ""package"", + ""files"": [ + ""System.Runtime.nuspec"" + ] + } + }, + ""projectFileDependencyGroups"": { + """": [ + ""System.Runtime [4.0.10-beta-*, )"" + ], + "".NETPlatform,Version=v5.0"": [] + }, + ""logs"": [ + { + ""code"": ""InvalidCode"", + ""level"": ""Error"", + ""message"": ""test log message"" + }, + { + ""code"": ""NU1000"", + ""level"": ""InvalidCode"", + ""message"": ""test log message"" + }, + { + ""code"": ""NU1000"", + ""level"": ""Error"", + ""message"": ""test log message"" + } + ] +}"; + LockFile lockFileObj = null; + IAssetsLogMessage logMessage = null; + using (var lockFile = new TempFile()) + { + + File.WriteAllText(lockFile, lockFileContent); + + // Act + lockFileObj = Read(lockFile, environmentVariableReader); + logMessage = lockFileObj?.LogMessages?.First(); + } + + + // Assert + Assert.NotNull(lockFileObj); + Assert.NotNull(logMessage); + Assert.Equal(1, lockFileObj.LogMessages.Count()); + Assert.Equal(LogLevel.Error, logMessage.Level); + Assert.Equal(NuGetLogCode.NU1000, logMessage.Code); + Assert.Null(logMessage.FilePath); + Assert.Equal(0, logMessage.StartLineNumber); + Assert.Equal(0, logMessage.EndLineNumber); + Assert.Equal(0, logMessage.StartColumnNumber); + Assert.Equal(0, logMessage.EndColumnNumber); + Assert.NotNull(logMessage.TargetGraphs); + Assert.Equal(0, logMessage.TargetGraphs.Count); + Assert.Equal("test log message", logMessage.Message); + } + + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsFullErrorMessage(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1460,8 +1548,7 @@ public void LockFileFormat_ReadsFullErrorMessage() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1482,8 +1569,9 @@ public void LockFileFormat_ReadsFullErrorMessage() Assert.Equal("test log message", logMessage.Message); } - [Fact] - public void LockFileFormat_SafeRead() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_SafeRead(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1544,7 +1632,7 @@ public void LockFileFormat_SafeRead() // Act var reader = new LockFileFormat(); - lockFileObj = FileUtility.SafeRead(lockFile, (stream, path) => reader.Read(stream, NullLogger.Instance, path)); + lockFileObj = FileUtility.SafeRead(lockFile, (stream, path) => reader.Read(stream, NullLogger.Instance, path, environmentVariableReader, true)); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1567,8 +1655,9 @@ public void LockFileFormat_SafeRead() } - [Fact] - public void LockFileFormat_ReadsWarningMessage() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsWarningMessage(IEnvironmentVariableReader environmentVariableReader) { // Arrange @@ -1629,8 +1718,7 @@ public void LockFileFormat_ReadsWarningMessage() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1652,8 +1740,9 @@ public void LockFileFormat_ReadsWarningMessage() Assert.Equal("test log message", logMessage.Message); } - [Fact] - public void LockFileFormat_ReadsWarningMessageWithoutWarningLevel() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsWarningMessageWithoutWarningLevel(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1712,8 +1801,7 @@ public void LockFileFormat_ReadsWarningMessageWithoutWarningLevel() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1736,8 +1824,9 @@ public void LockFileFormat_ReadsWarningMessageWithoutWarningLevel() } - [Fact] - public void LockFileFormat_ReadsMultipleMessages() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsMultipleMessages(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1807,8 +1896,7 @@ public void LockFileFormat_ReadsMultipleMessages() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); } @@ -1825,8 +1913,9 @@ public void LockFileFormat_ReadsMultipleMessages() Assert.Equal(1, lockFileObj.LogMessages.Where(m => m.Code == NuGetLogCode.NU1001).Count()); } - [Fact] - public void LockFileFormat_ReadsLogMessageWithSameFilePathAndProjectPath() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsLogMessageWithSameFilePathAndProjectPath(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1881,8 +1970,7 @@ public void LockFileFormat_ReadsLogMessageWithSameFilePathAndProjectPath() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1904,8 +1992,9 @@ public void LockFileFormat_ReadsLogMessageWithSameFilePathAndProjectPath() Assert.Equal("test log message", logMessage.Message); } - [Fact] - public void LockFileFormat_ReadsLogMessageWithNoFilePath() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsLogMessageWithNoFilePath(IEnvironmentVariableReader environmentVariableReader) { // Arrange var lockFileContent = @"{ @@ -1959,8 +2048,7 @@ public void LockFileFormat_ReadsLogMessageWithNoFilePath() File.WriteAllText(lockFile, lockFileContent); // Act - var reader = new LockFileFormat(); - lockFileObj = reader.Read(lockFile); + lockFileObj = Read(lockFile, environmentVariableReader); logMessage = lockFileObj?.LogMessages?.First(); } @@ -1982,8 +2070,9 @@ public void LockFileFormat_ReadsLogMessageWithNoFilePath() Assert.Equal("test log message", logMessage.Message); } - [Fact] - public void LockFileFormat_ReadsLockFileWithTools() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsLockFileWithTools(IEnvironmentVariableReader environmentVariableReader) { var lockFileContent = @"{ ""version"": 1, @@ -2018,8 +2107,7 @@ public void LockFileFormat_ReadsLockFileWithTools() "".NETPlatform,Version=v5.0"": [] } }"; - var lockFileFormat = new LockFileFormat(); - var lockFile = lockFileFormat.Parse(lockFileContent, "In Memory"); + var lockFile = Parse(lockFileContent, "In Memory", environmentVariableReader); Assert.Equal(1, lockFile.Version); @@ -2052,8 +2140,9 @@ public void LockFileFormat_ReadsLockFileWithTools() Assert.Empty(netPlatDepGroup.Dependencies); } - [Fact] - public void LockFileFormat_ReadsLockFileWithEmbedAssemblies() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFileFormat_ReadsLockFileWithEmbedAssemblies(IEnvironmentVariableReader environmentVariableReader) { var lockFileContent = @"{ ""version"": 1, @@ -2094,8 +2183,7 @@ public void LockFileFormat_ReadsLockFileWithEmbedAssemblies() } }"; - var lockFileFormat = new LockFileFormat(); - var lockFile = lockFileFormat.Parse(lockFileContent, "In Memory"); + var lockFile = Parse(lockFileContent, "In Memory", environmentVariableReader); Assert.Equal(1, lockFile.Version); @@ -2295,5 +2383,24 @@ public void LockFileFormat_WritesCentralTransitiveDependencyGroups() // Assert Assert.Equal(expected.ToString(), output.ToString()); } + + private LockFile Read(string filePath, IEnvironmentVariableReader environmentVariableReader) + { + var reader = new LockFileFormat(); + using (var stream = File.OpenRead(filePath)) + { + return reader.Read(stream, NullLogger.Instance, filePath, environmentVariableReader, true); + } + } + + private LockFile Parse(string lockFileContent, string path, IEnvironmentVariableReader environmentVariableReader) + { + var reader = new LockFileFormat(); + byte[] byteArray = Encoding.UTF8.GetBytes(lockFileContent); + using (var stream = new MemoryStream(byteArray)) + { + return reader.Read(stream, NullLogger.Instance, path, environmentVariableReader, true); + } + } } } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs new file mode 100644 index 00000000000..6224637214d --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs @@ -0,0 +1,61 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Test.Utility; + +namespace NuGet.ProjectModel +{ + public static class LockFileParsingEnvironmentVariable + { + public static IEnumerable TestEnvironmentVariableReader() + { + return GetTestEnvironmentVariableReader(); + } + + public static IEnumerable TestEnvironmentVariableReader(object value1) + { + return GetTestEnvironmentVariableReader(value1); + } + + public static IEnumerable TestEnvironmentVariableReader(object value1, object value2) + { + return GetTestEnvironmentVariableReader(value1, value2); + } + + public static IEnumerable TestEnvironmentVariableReader(object value1, object value2, object value3) + { + return GetTestEnvironmentVariableReader(value1, value2, value3); + } + + private static IEnumerable GetTestEnvironmentVariableReader(params object[] objects) + { + var UseNjForFileTrue = new List { + new TestEnvironmentVariableReader( + new Dictionary() + { + [JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING] = bool.TrueString + }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: true") + }; + var UseNjForFileFalse = new List { + new TestEnvironmentVariableReader( + new Dictionary() + { + [JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING] = bool.FalseString + }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: false") + }; + + if (objects != null) + { + UseNjForFileFalse.AddRange(objects); + UseNjForFileTrue.AddRange(objects); + } + + return new List + { + UseNjForFileTrue.ToArray(), + UseNjForFileFalse.ToArray() + }; + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileTests.cs index 8131591068f..8875d8e0ddd 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text; using FluentAssertions; using NuGet.Common; using NuGet.Frameworks; @@ -854,12 +855,13 @@ public void LockFile_ConsiderCentralTransitiveDependencyGroupsForEquality() Assert.Equal(lockFile_1_2.GetHashCode(), lockFile_11_22.GetHashCode()); } - [Fact] - public void LockFile_GetTarget_WithNuGetFramework_ReturnsCorrectLockFileTarget() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFile_GetTarget_WithNuGetFramework_ReturnsCorrectLockFileTarget(IEnvironmentVariableReader environmentVariableReader) { // Arrange var expectedJson = ResourceTestUtility.GetResource("NuGet.ProjectModel.Test.compiler.resources.sample.assets.json", typeof(LockFileTests)); - var lockFile = new LockFileFormat().Parse(expectedJson, Path.GetTempPath()); + var lockFile = Parse(expectedJson, Path.GetTempPath(), environmentVariableReader); NuGetFramework nuGetFramework = NuGetFramework.ParseComponents(".NETCoreApp,Version=v5.0", "Windows,Version=7.0"); // Act @@ -869,12 +871,13 @@ public void LockFile_GetTarget_WithNuGetFramework_ReturnsCorrectLockFileTarget() target.TargetFramework.Should().Be(nuGetFramework); } - [Fact] - public void LockFile_GetTarget_WithAlias_ReturnsCorrectLockFileTarget() + [Theory] + [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] + public void LockFile_GetTarget_WithAlias_ReturnsCorrectLockFileTarget(IEnvironmentVariableReader environmentVariableReader) { // Arrange var expectedJson = ResourceTestUtility.GetResource("NuGet.ProjectModel.Test.compiler.resources.sample.assets.json", typeof(LockFileTests)); - var lockFile = new LockFileFormat().Parse(expectedJson, Path.GetTempPath()); + var lockFile = Parse(expectedJson, Path.GetTempPath(), environmentVariableReader); NuGetFramework nuGetFramework = NuGetFramework.ParseComponents(".NETCoreApp,Version=v5.0", "Windows,Version=7.0"); // Act @@ -883,5 +886,15 @@ public void LockFile_GetTarget_WithAlias_ReturnsCorrectLockFileTarget() // Assert target.TargetFramework.Should().Be(nuGetFramework); } + + private LockFile Parse(string lockFileContent, string path, IEnvironmentVariableReader environmentVariableReader) + { + var reader = new LockFileFormat(); + byte[] byteArray = Encoding.UTF8.GetBytes(lockFileContent); + using (var stream = new MemoryStream(byteArray)) + { + return reader.Read(stream, NullLogger.Instance, path, environmentVariableReader, true); + } + } } } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTestUtility.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTestUtility.cs index a5b3cbfa8ed..0e21266b564 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTestUtility.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTestUtility.cs @@ -21,7 +21,9 @@ public static PackageSpec GetPackageSpec(string json, IEnvironmentVariableReader var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)); var streamReader = new StreamReader(ms); var jsonReader = new JsonTextReader(streamReader); +#pragma warning disable CS0612 // Type or member is obsolete return JsonPackageSpecReader.GetPackageSpec(jsonReader, "project", "project.json", environmentReader); +#pragma warning restore CS0612 // Type or member is obsolete } public static PackageSpec RoundTripJson(string json, IEnvironmentVariableReader environmentReader) diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/StringExtensionTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/StringExtensionTests.cs new file mode 100644 index 00000000000..ffcbeb2014f --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/StringExtensionTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace NuGet.ProjectModel.Test +{ + public class StringExtensionTests + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void SplitInTwo_WithNullOrEmptyString_ReturnStringAndNull(string s) + { + var result = s.SplitInTwo('/'); + Assert.Equal(s, result.firstPart); + Assert.Null(result.secondPart); + } + + [Theory] + [InlineData("part1/part2", "part1", "part2")] + [InlineData("part1/part2/NotPart3", "part1", "part2/NotPart3")] + public void SplitInTwo_WithSeperator_ReturnStringInTwoParts(string s, string expectedFirstPart, string expectedSecondPart) + { + var results = s.SplitInTwo('/'); + Assert.Equal(expectedFirstPart, results.firstPart); + Assert.Equal(expectedSecondPart, results.secondPart); + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonReaderExtensionsTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonReaderExtensionsTests.cs new file mode 100644 index 00000000000..0c60a72b4e3 --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonReaderExtensionsTests.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Text; +using System.Text.Json; +using Xunit; + +namespace NuGet.ProjectModel.Test +{ + [UseCulture("")] // Fix tests failing on systems with non-English locales + public class Utf8JsonReaderExtensionsTests + { + [Theory] + [InlineData("null", null)] + [InlineData("true", "True")] + [InlineData("false", "False")] + [InlineData("-2", "-2")] + [InlineData("9223372036854775807", "9223372036854775807")] + [InlineData("3.14", "3.14")] + [InlineData("\"b\"", "b")] + public void ReadTokenAsString_WhenValueIsConvertibleToString_ReturnsValueAsString( + string value, + string expectedResult) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + var reader = new Utf8JsonReader(encodedBytes); + reader.Read(); + reader.Read(); + reader.Read(); + string actualResult = reader.ReadTokenAsString(); + Assert.Equal(expectedResult, actualResult); + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonStreamReaderTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonStreamReaderTests.cs new file mode 100644 index 00000000000..d0177515c10 --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/Utf8JsonStreamReaderTests.cs @@ -0,0 +1,918 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using Moq; +using Xunit; + +namespace NuGet.ProjectModel.Test +{ + [UseCulture("")] // Fix tests failing on systems with non-English locales + public class Utf8JsonStreamReaderTests + { + private static readonly string JsonWithOverflowObject = "{\"object1\":{\"a\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\"},\"object2\":{\"a\":\"abcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyz\"}}"; + private static readonly string JsonWithoutOverflow = "{\"object1\":{\"a\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\"}}"; + private static readonly string JsonWithOverflow = "{\"object1\":{\"a\":\"abcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyz\"}, \"object2\": {\"a\":\"abcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyz\"}, \"object3\":{\"a\":\"abcdefghijklmnopqrstuvwxyz\",\"b\":\"abcdefghijklmnopqrstuvwxyz\",\"c\":\"abcdefghijklmnopqrstuvwxyz\",\"d\":\"abcdefghijklmnopqrstuvwxyz\",\"e\":\"abcdefghijklmnopqrstuvwxyz\",\"f\":\"abcdefghijklmnopqrstuvwxyz\",\"g\":\"abcdefghijklmnopqrstuvwxyz\",\"h\":\"abcdefghijklmnopqrstuvwxyz\",\"i\":\"abcdefghijklmnopqrstuvwxyz\",\"j\":\"abcdefghijklmnopqrstuvwxyz\",\"k\":\"abcdefghijklmnopqrstuvwxyz\",\"l\":\"abcdefghijklmnopqrstuvwxyz\",\"m\":\"abcdefghijklmnopqrstuvwxyz\",\"n\":\"abcdefghijklmnopqrstuvwxyz\",\"o\":\"abcdefghijklmnopqrstuvwxyz\",\"p\":\"abcdefghijklmnopqrstuvwxyz\",\"q\":\"abcdefghijklmnopqrstuvwxyz\",\"r\":\"abcdefghijklmnopqrstuvwxyz\",\"s\":\"abcdefghijklmnopqrstuvwxyz\",\"t\":\"abcdefghijklmnopqrstuvwxyz\",\"u\":\"abcdefghijklmnopqrstuvwxyz\"}}"; + private static readonly string SmallJson = "{\"object1\":{\"a\":\"abcdefghijklmnopqrstuvwxyz\"}}"; + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenStreamIsNull_Throws() + { + Assert.Throws(() => + { + using var reader = new Utf8JsonStreamReader(null); + }); + } + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenBufferToSmall_Throws() + { + Assert.Throws(() => + { + var json = "{}"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + using (var reader = new Utf8JsonStreamReader(stream, 10)) + { + } + }); + } + + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenEmptyJson_Throws() + { + Assert.ThrowsAny(() => + { + var json = ""; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + using (var reader = new Utf8JsonStreamReader(stream)) + { + } + }); + } + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenEmptySream_Throws() + { + Assert.ThrowsAny(() => + { + using (var stream = new MemoryStream(Array.Empty())) + using (var reader = new Utf8JsonStreamReader(stream)) + { + } + }); + } + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenStreamStartsWithUtf8Bom_SkipThem() + { + var json = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()) + "{}"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(5, stream.Position); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + } + } + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenStreamStartsWithoutUtf8Bom_ReadFromStart() + { + var json = "{}"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(2, stream.Position); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + } + } + + [Fact] + public void Utf8JsonStreamReaderCtr_WhenReadingWithOverflow_FinalBlockFalse() + { + var json = Encoding.UTF8.GetBytes(JsonWithOverflowObject); + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024)) + { + Assert.False(reader.IsFinalBlock); + } + } + + [Fact] + public void Read_WhenReadingMalformedJsonString_Throws() + { + var json = Encoding.UTF8.GetBytes("{\"a\":\"string}"); + + Assert.ThrowsAny(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.True(reader.IsFinalBlock); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + } + }); + } + + [Fact] + public void Read_WhenReadingMalformedJson_Throws() + { + var json = Encoding.UTF8.GetBytes("{\"a\":\"string\"}ohno"); + Assert.ThrowsAny(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.True(reader.IsFinalBlock); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + reader.Read(); + reader.Read(); + reader.Read(); + } + }); + } + + [Fact] + public void Read_WhenReadingSmallJson_Read() + { + var json = Encoding.UTF8.GetBytes(SmallJson); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.True(reader.IsFinalBlock); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.String, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + } + } + + [Fact] + public void Read_WhenReadingSmallJsonPastEnd_Read() + { + var json = Encoding.UTF8.GetBytes(SmallJson); + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.True(reader.IsFinalBlock); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.String, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + Assert.False(reader.Read()); + } + } + + [Fact] + public void Read_WhenReadingWithoutOverflow_Read() + { + var json = Encoding.UTF8.GetBytes(JsonWithoutOverflow); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.True(reader.IsFinalBlock); + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + } + } + + [Fact] + public void Read_WhenReadingWithOverflow_ReadNextBuffer() + { + var json = Encoding.UTF8.GetBytes(JsonWithOverflowObject); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, mock.Object)) + { + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.PropertyName && reader.GetString() == "r") + { + break; + } + } + reader.Read(); + mock.Verify(m => m.Rent(1024), Times.Exactly(1)); + Assert.Equal(JsonTokenType.String, reader.TokenType); + Assert.Equal("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", reader.GetString()); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + Assert.Equal("s", reader.GetString()); + } + } + + [Fact] + public void Read_WhenReadingWithLargeToken_ResizeBuffer() + { + var json = Encoding.UTF8.GetBytes("{\"largeToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"smallToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\"}"); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, mock.Object)) + { + reader.Read(); + reader.Read(); + + mock.Verify(m => m.Rent(1024), Times.Exactly(1)); + mock.Verify(m => m.Rent(2048), Times.Exactly(1)); + mock.Verify(m => m.Return(It.IsAny(), true), Times.Exactly(1)); + Assert.Equal(JsonTokenType.String, reader.TokenType); + Assert.Equal("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + reader.GetString()); + } + } + + [Fact] + public void Read_WithLargeToken_WhenReadPastFinal_ReadReturnsFalse() + { + var json = Encoding.UTF8.GetBytes("{\"largeToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\",\"smallToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\"}"); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, mock.Object)) + { + reader.Read(); + reader.Read(); + reader.Read(); + reader.Read(); + reader.Read(); + mock.Verify(m => m.Rent(1024), Times.Exactly(1)); + mock.Verify(m => m.Rent(2048), Times.Exactly(1)); + mock.Verify(m => m.Return(It.IsAny(), true), Times.Exactly(1)); + Assert.False(reader.Read()); + } + } + + [Fact] + public void Read_WhenReadingWithOverflowToBufferSize_LoadNextBuffer() + { + var json = Encoding.UTF8.GetBytes("{\"largeToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst\",\"smallToken\":\"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\"}"); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024)) + { + reader.Read(); + reader.Read(); + reader.Read(); + + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + Assert.Equal("smallToken", reader.GetString()); + Assert.True(reader.Read()); + Assert.Equal(JsonTokenType.String, reader.TokenType); + Assert.Equal("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", reader.GetString()); + } + } + + [Fact] + public void Dispose_NoErrors() + { + var json = Encoding.UTF8.GetBytes(SmallJson); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, arrayPool: mock.Object)) + { + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + } + mock.Verify(m => m.Return(It.IsAny(), true), Times.Exactly(1)); + } + + [Fact] + public void Dispose_Read_ObjectDisposedException() + { + var json = Encoding.UTF8.GetBytes(SmallJson); + Assert.Throws(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Dispose(); + reader.Read(); + } + }); + } + + [Fact] + public void Dispose_Skip_ObjectDisposedException() + { + var json = Encoding.UTF8.GetBytes(SmallJson); + Assert.Throws(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Dispose(); + reader.Skip(); + } + }); + } + + [Theory] + [InlineData("{\"object1\": { \"a\":\"asdad\" }")] + [InlineData("{\"object1\": { \"a\":\"asdad }}")] + [InlineData("{\"object1\": \"a\":\"asdad\" }}")] + public void Skip_WhenReadingWithMalformedJson(string malformedJson) + { + var json = Encoding.UTF8.GetBytes(malformedJson); + + Assert.ThrowsAny(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Skip(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + } + }); + } + + [Fact] + public void Skip_WhenReadingWithoutOverflow_SkipObject() + { + var json = Encoding.UTF8.GetBytes(JsonWithoutOverflow); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(JsonTokenType.StartObject, reader.TokenType); + reader.Skip(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + } + } + + [Fact] + public void Skip_WhenReadingWithOverflow_Skip() + { + var json = Encoding.UTF8.GetBytes(JsonWithOverflow); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, mock.Object)) + { + reader.Read(); + reader.Skip(); + reader.Read(); + reader.Skip(); + Assert.Equal(JsonTokenType.EndObject, reader.TokenType); + reader.Read(); + Assert.Equal("object3", reader.GetString()); + mock.Verify(m => m.Rent(1024), Times.Exactly(1)); + } + } + + [Fact] + public void Skip_WhenReadingWithOverflowObject_ResizeBuffer() + { + var json = Encoding.UTF8.GetBytes(JsonWithOverflowObject); + var mock = SetupMockArrayBuffer(); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream, 1024, mock.Object)) + { + reader.Read(); + reader.Skip(); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + Assert.Equal("object2", reader.GetString()); + mock.Verify(m => m.Rent(1024), Times.Exactly(1)); + mock.Verify(m => m.Rent(2048), Times.Exactly(1)); + mock.Verify(m => m.Return(It.IsAny(), true), Times.Exactly(1)); + } + } + + [Fact] + public void ReadNextTokenAsString_WhenCalled_AdvanceToken() + { + var json = Encoding.UTF8.GetBytes("{\"token\":\"value\"}"); + + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + var result = reader.ReadNextTokenAsString(); + Assert.Equal(JsonTokenType.String, reader.TokenType); + Assert.Equal("value", result); + } + } + + [Fact] + public void ReadNextTokenAsString_WithMalformedJson_GetException() + { + var json = Encoding.UTF8.GetBytes("{\"token\":\"value}"); + Assert.ThrowsAny(() => + { + using (var stream = new MemoryStream(json)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + reader.ReadNextTokenAsString(); + } + }); + } + + [Theory] + [InlineData("true", JsonTokenType.True)] + [InlineData("false", JsonTokenType.False)] + [InlineData("-2", JsonTokenType.Number)] + [InlineData("3.14", JsonTokenType.Number)] + [InlineData("{}", JsonTokenType.StartObject)] + [InlineData("[]", JsonTokenType.StartArray)] + [InlineData("[true]", JsonTokenType.StartArray)] + [InlineData("[-2]", JsonTokenType.StartArray)] + [InlineData("[3.14]", JsonTokenType.StartArray)] + [InlineData("[\"a\", \"b\"]", JsonTokenType.StartArray)] + public void ReadDelimitedString_WhenValueIsNotString_Throws(string value, JsonTokenType expectedTokenType) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + var tokenType = JsonTokenType.None; + var exceptionThrown = Assert.Throws(() => + { + using var stream = new MemoryStream(encodedBytes); + using var reader = new Utf8JsonStreamReader(stream); + reader.Read(); + try + { + reader.ReadDelimitedString(); + } + finally + { + tokenType = reader.TokenType; + } + }); + Assert.Null(exceptionThrown.InnerException); + Assert.Equal(expectedTokenType, tokenType); + } + + [Fact] + public void ReadDelimitedString_WhenValueIsString_ReturnsValue() + { + const string expectedResult = "b"; + var json = $"{{\"a\":\"{expectedResult}\"}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + IEnumerable actualResults = reader.ReadDelimitedString(); + Assert.Collection(actualResults, actualResult => Assert.Equal(expectedResult, actualResult)); + Assert.Equal(JsonTokenType.String, reader.TokenType); + } + } + + [Theory] + [InlineData("b,c,d")] + [InlineData("b c d")] + public void ReadDelimitedString_WhenValueIsDelimitedString_ReturnsValues(string value) + { + string[] expectedResults = value.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); + var json = $"{{\"a\":\"{value}\"}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + IEnumerable actualResults = reader.ReadDelimitedString(); + Assert.Equal(expectedResults, actualResults); + Assert.Equal(JsonTokenType.String, reader.TokenType); + } + } + + [Theory] + [InlineData("null")] + [InlineData("\"b\"")] + [InlineData("{}")] + public void ReadStringArrayAsIList_WhenValueIsNotArray_ReturnsNull(string value) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + reader.Read(); + Assert.NotEqual(JsonTokenType.PropertyName, reader.TokenType); + IList actualValues = reader.ReadStringArrayAsIList(); + Assert.Null(actualValues); + } + } + + [Fact] + public void ReadStringArrayAsIList_WhenValueIsEmptyArray_ReturnsNull() + { + var encodedBytes = Encoding.UTF8.GetBytes("{\"a\":[]}"); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + reader.Read(); + Assert.NotEqual(JsonTokenType.PropertyName, reader.TokenType); + IList actualValues = reader.ReadStringArrayAsIList(); + Assert.Null(actualValues); + } + } + + [Fact] + public void ReadStringArrayAsIList_WithSupportedTypes_ReturnsStringArray() + { + var encodedBytes = Encoding.UTF8.GetBytes("[\"a\",-2,3.14,true,null]"); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + IList actualValues = reader.ReadStringArrayAsIList(); + + Assert.Collection( + actualValues, + actualValue => Assert.Equal("a", actualValue), + actualValue => Assert.Equal("-2", actualValue), + actualValue => Assert.Equal("3.14", actualValue), + actualValue => Assert.Equal("True", actualValue), + actualValue => Assert.Null(actualValue)); + Assert.Equal(JsonTokenType.EndArray, reader.TokenType); + } + } + + [Theory] + [InlineData("[]")] + [InlineData("{}")] + public void ReadStringArrayAsIList_WithUnsupportedTypes_Throws(string element) + { + var encodedBytes = Encoding.UTF8.GetBytes($"[{element}]"); + Assert.Throws(() => + { + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.ReadStringArrayAsIList(); + } + }); + } + + + [Theory] + [InlineData("true", true)] + [InlineData("false", false)] + public void ReadNextTokenAsBoolOrFalse_WithValidValues_ReturnsBoolean(string value, bool expectedResult) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + bool actualResult = reader.ReadNextTokenAsBoolOrFalse(); + Assert.Equal(expectedResult, actualResult); + } + } + + [Theory] + [InlineData("\"words\"")] + [InlineData("-3")] + [InlineData("3.3")] + [InlineData("[]")] + [InlineData("{}")] + public void ReadNextTokenAsBoolOrFalse_WithInvalidValues_ReturnsFalse(string value) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + bool actualResult = reader.ReadNextTokenAsBoolOrFalse(); + Assert.False(actualResult); + } + } + + [Fact] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsNull_ReturnsNull() + { + const string json = "{\"a\":null}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + Assert.Null(actualResults); + Assert.Equal(JsonTokenType.Null, reader.TokenType); + } + } + + [Theory] + [InlineData("true", JsonTokenType.True)] + [InlineData("false", JsonTokenType.False)] + [InlineData("-2", JsonTokenType.Number)] + [InlineData("3.14", JsonTokenType.Number)] + [InlineData("{}", JsonTokenType.StartObject)] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsNotString_ReturnsNull( + string value, + JsonTokenType expectedTokenType) + { + var json = $"{{\"a\":{value}}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Null(actualResults); + Assert.Equal(expectedTokenType, reader.TokenType); + } + } + + [Fact] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsString_ReturnsValue() + { + const string expectedResult = "b"; + var json = $"{{\"a\":\"{expectedResult}\"}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Collection(actualResults, actualResult => Assert.Equal(expectedResult, actualResult)); + Assert.Equal(JsonTokenType.String, reader.TokenType); + } + } + + [Theory] + [InlineData("b,c,d")] + [InlineData("b c d")] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsDelimitedString_ReturnsValue(string expectedResult) + { + var json = $"{{\"a\":\"{expectedResult}\"}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Collection(actualResults, actualResult => Assert.Equal(expectedResult, actualResult)); + Assert.Equal(JsonTokenType.String, reader.TokenType); + } + } + + [Fact] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsEmptyArray_ReturnsEmptyList() + { + const string json = "{\"a\":[]}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IReadOnlyList actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Empty(actualResults); + Assert.Equal(JsonTokenType.EndArray, reader.TokenType); + } + } + + [Theory] + [InlineData("null", null)] + [InlineData("true", "True")] + [InlineData("-2", "-2")] + [InlineData("3.14", "3.14")] + [InlineData("\"b\"", "b")] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsConvertibleToString_ReturnsValueAsString( + string value, + string expectedResult) + { + var json = $"{{\"a\":[{value}]}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Collection(actualResults, actualResult => Assert.Equal(expectedResult, actualResult)); + Assert.Equal(JsonTokenType.EndArray, reader.TokenType); + } + } + + [Theory] + [InlineData("[]", JsonTokenType.StartArray)] + [InlineData("{}", JsonTokenType.StartObject)] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsNotConvertibleToString_ReturnsValueAsString( + string value, + JsonTokenType expectedToken) + { + var json = $"{{\"a\":[{value}]}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + var tokenType = JsonTokenType.None; + var exceptionThrown = Assert.Throws(() => + { + using var stream = new MemoryStream(encodedBytes); + using var reader = new Utf8JsonStreamReader(stream); + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + try + { + reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + } + finally + { + tokenType = reader.TokenType; + } + }); + Assert.Equal(expectedToken, tokenType); + } + + [Fact] + public void ReadNextStringOrArrayOfStringsAsReadOnlyList_WhenValueIsArrayOfStrings_ReturnsValues() + { + string[] expectedResults = { "b", "c" }; + var json = $"{{\"a\":[{string.Join(",", expectedResults.Select(expectedResult => $"\"{expectedResult}\""))}]}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.Read(); + Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); + + IEnumerable actualResults = reader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); + + Assert.Equal(expectedResults, actualResults); + Assert.Equal(JsonTokenType.EndArray, reader.TokenType); + } + } + + [Fact] + public void ReadObjectAsList_WithValidJson_ReturnsValue() + { + var json = "{ \"a\": { \"property1\": \"1\" },\"b\": { \"property1\": \"1\" }, \"c\": { \"property1\": \"1\" }}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + var results = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + Assert.Equal(3, results.Count); + } + } + + [Theory] + [InlineData("{}")] + [InlineData("null")] + public void ReadObjectAsList_WithEmptyValues_ReturnsEmptyArray(string json) + { + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + var results = reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + Assert.Equal(0, results.Count); + Assert.IsType(Array.Empty().GetType(), results); + } + } + + [Fact] + public void ReadObjectAsList_WithInvalidValue_ThrowsException() + { + var json = "\"a\": { \"property1\": \"1\" }"; + + var encodedBytes = Encoding.UTF8.GetBytes(json); + Assert.Throws(() => + { + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + reader.ReadObjectAsList(Utf8JsonReaderExtensions.LockFileItemConverter); + } + }); + } + + [Fact] + public void ReadStringArrayAsReadOnlyListFromArrayStart_WhenValuesAreConvertibleToString_ReturnsReadOnlyList() + { + const string json = "[null, true, -2, 3.14, \"a\"]"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + using (var stream = new MemoryStream(encodedBytes)) + using (var reader = new Utf8JsonStreamReader(stream)) + { + Assert.Equal(JsonTokenType.StartArray, reader.TokenType); + + IEnumerable actualResults = reader.ReadStringArrayAsReadOnlyListFromArrayStart(); + + Assert.Collection( + actualResults, + actualResult => Assert.Null(null), + actualResult => Assert.Equal("True", actualResult), + actualResult => Assert.Equal("-2", actualResult), + actualResult => Assert.Equal("3.14", actualResult), + actualResult => Assert.Equal("a", actualResult)); + Assert.Equal(JsonTokenType.EndArray, reader.TokenType); + } + } + + [Theory] + [InlineData("[]", JsonTokenType.StartArray)] + [InlineData("{}", JsonTokenType.StartObject)] + public void ReadStringArrayAsReadOnlyListFromArrayStart_WhenValuesAreNotConvertibleToString_Throws( + string value, + JsonTokenType expectedToken) + { + var json = $"[{value}]"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + var tokenType = JsonTokenType.None; + var exceptionThrown = Assert.Throws(() => + { + using var stream = new MemoryStream(encodedBytes); + using var reader = new Utf8JsonStreamReader(stream); + Assert.Equal(JsonTokenType.StartArray, reader.TokenType); + try + { + reader.ReadStringArrayAsReadOnlyListFromArrayStart(); + } + finally + { + tokenType = reader.TokenType; + } + }); + Assert.Equal(expectedToken, tokenType); + } + + [Theory] + [InlineData("value")] + [InlineData("")] + public void ValueTextEquals_WithValidData_ReturnTrue(string value) + { + var json = $"{{ \"{value}\":\"property\"}}"; + var encodedBytes = Encoding.UTF8.GetBytes(json); + var utf8Bytes = Encoding.UTF8.GetBytes(value); + using var stream = new MemoryStream(encodedBytes); + using var reader = new Utf8JsonStreamReader(stream); + reader.Read(); + Assert.True(reader.ValueTextEquals(utf8Bytes)); + } + + private Mock> SetupMockArrayBuffer() + { + Mock> mock = new Mock>(); + mock.Setup(m => m.Rent(1024)).Returns(new byte[1024]); + mock.Setup(m => m.Rent(2048)).Returns(new byte[2048]); + mock.Setup(m => m.Return(It.IsAny(), It.IsAny())); + + return mock; + } + } +} diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/Utility/CommonUtility.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/Utility/CommonUtility.cs index 63fc7d6c0e9..0426f096d49 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/Utility/CommonUtility.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/Utility/CommonUtility.cs @@ -396,7 +396,6 @@ private static LockFile GetAssetsFileWithRetry(string path) { var timeout = TimeSpan.FromSeconds(20); var timer = Stopwatch.StartNew(); - string content = null; do { @@ -405,9 +404,8 @@ private static LockFile GetAssetsFileWithRetry(string path) { try { - content = File.ReadAllText(path); var format = new LockFileFormat(); - return format.Parse(content, path); + return format.Read(path); } catch { diff --git a/test/TestUtilities/Test.Utility/TestEnvironmentVariableReader.cs b/test/TestUtilities/Test.Utility/TestEnvironmentVariableReader.cs index d2556660e89..ef5b209b8c8 100644 --- a/test/TestUtilities/Test.Utility/TestEnvironmentVariableReader.cs +++ b/test/TestUtilities/Test.Utility/TestEnvironmentVariableReader.cs @@ -11,6 +11,8 @@ public sealed class TestEnvironmentVariableReader : IEnvironmentVariableReader { private readonly IReadOnlyDictionary _variables; + private readonly string _toStringSuffix; + public static IEnvironmentVariableReader EmptyInstance { get; } = new TestEnvironmentVariableReader(); private TestEnvironmentVariableReader() @@ -18,9 +20,10 @@ private TestEnvironmentVariableReader() _variables = new Dictionary(); } - public TestEnvironmentVariableReader(IReadOnlyDictionary variables) + public TestEnvironmentVariableReader(IReadOnlyDictionary variables, string toStringSuffix = null) { _variables = variables ?? throw new ArgumentNullException(nameof(variables)); + _toStringSuffix = toStringSuffix; } public string GetEnvironmentVariable(string variable) @@ -32,5 +35,14 @@ public string GetEnvironmentVariable(string variable) return null; } + + public override string ToString() + { + if (string.IsNullOrEmpty(_toStringSuffix)) + { + return base.ToString(); + } + return $"{base.ToString()}({_toStringSuffix})"; + } } }