diff --git a/src/Sarif.Converters.UnitTests/FortifyFprConverterTests.cs b/src/Sarif.Converters.UnitTests/FortifyFprConverterTests.cs index 1afb35ddb..823785384 100644 --- a/src/Sarif.Converters.UnitTests/FortifyFprConverterTests.cs +++ b/src/Sarif.Converters.UnitTests/FortifyFprConverterTests.cs @@ -1,13 +1,16 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.CodeAnalysis.Sarif.TestUtilities; using Xunit; using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.Sarif.Converters { - public class FortifyFprConverterTests : FileDiffingTests + public class FortifyFprConverterTests : FileDiffingTests, IClassFixture { + public class FortifyFprConverterTestsFixture : DeletesOutputsDirectoryOnClassInitializationFixture { } + protected override string TestLogResourceNameRoot => "Microsoft.CodeAnalysis.Sarif.Converters.UnitTests.TestData." + TypeUnderTest; public FortifyFprConverterTests(ITestOutputHelper outputHelper) : base(outputHelper) { } diff --git a/src/Sarif.TestUtilities/DeletesOutputsDirectoryOnClassInitializationFixture.cs b/src/Sarif.TestUtilities/DeletesOutputsDirectoryOnClassInitializationFixture.cs new file mode 100644 index 000000000..e999b3b8a --- /dev/null +++ b/src/Sarif.TestUtilities/DeletesOutputsDirectoryOnClassInitializationFixture.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT +// license. See LICENSE file in the project root for full license information. + +using System.IO; + +namespace Microsoft.CodeAnalysis.Sarif.TestUtilities +{ + /// + /// This class is an XUnit "class fixture." If a test class is marked with the interface + /// IClassFixture<T>, then before XUnit runs any tests from the class, it will instantiate + /// T (which must have a parameterless constructor). If T implements IDisposable, then after + /// xUnit runs the last test method from the class, it will dispose the fixture. This mechanism + /// allows class-level setup and teardown (although I don't know why they don't just reflect + /// for static methods like ClassSetup and ClassTeardown). + /// + /// See https://xunit.github.io/docs/shared-context for more information about xUnit class fixtures. + /// + /// This particular fixture deletes any existing test output files that may have been produced + /// by a previous run. It is designed for use on test classes that derive from FileDiffingTests. + /// It is required because FileDiffingTests emits the outputs from each test to a common directory, + /// to allow diffing an entire directory of failing tests. If each test case deleted this directory, + /// then at the end it would contain only the output from the last failing test. + /// + /// Each class that derives from FileDiffingTests can declare its own derived fixture class if + /// it wants to override the virtual TypeUnderTest or OutputFolderPath properties, but there seems + /// no good reason to do this. + /// + public abstract class DeletesOutputsDirectoryOnClassInitializationFixture + { + protected virtual string TypeUnderTest => this.GetType().Name.Substring(0, this.GetType().Name.Length - "TestsFixture".Length); + + protected virtual string OutputFolderPath => Path.Combine(Path.GetDirectoryName(this.GetType().Assembly.Location), "UnitTestOutput." + TypeUnderTest); + + public DeletesOutputsDirectoryOnClassInitializationFixture() + { + if (Directory.Exists(OutputFolderPath)) + { + Directory.Delete(OutputFolderPath, recursive: true); + } + } + } +} diff --git a/src/Sarif.TestUtilities/FileDiffingTests.cs b/src/Sarif.TestUtilities/FileDiffingTests.cs index 3e257ef67..83c3057bb 100644 --- a/src/Sarif.TestUtilities/FileDiffingTests.cs +++ b/src/Sarif.TestUtilities/FileDiffingTests.cs @@ -13,6 +13,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; +using Xunit; using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.Sarif @@ -39,11 +40,6 @@ public FileDiffingTests(ITestOutputHelper outputHelper, bool testProducesSarifCu _outputHelper = outputHelper; _testProducesSarifCurrentVersion = testProducesSarifCurrentVersion; - if (Directory.Exists(OutputFolderPath)) - { - Directory.Delete(OutputFolderPath, recursive: true); - } - Directory.CreateDirectory(OutputFolderPath); } @@ -57,23 +53,24 @@ public FileDiffingTests(ITestOutputHelper outputHelper, bool testProducesSarifCu protected virtual string TestLogResourceNameRoot => "Microsoft.CodeAnalysis.Sarif.UnitTests.TestData." + TypeUnderTest; - protected virtual string ConstructTestOutputFromInputResource(string inputResource) { return string.Empty; } + protected virtual string ConstructTestOutputFromInputResource(string inputResourceName) { return string.Empty; } protected virtual bool RebaselineExpectedResults => false; - protected virtual void RunTest(string resourceName) + protected virtual void RunTest(string inputResourceName, string expectedOutputResourceName = null) { + expectedOutputResourceName = expectedOutputResourceName ?? inputResourceName; // When retrieving constructed test content, we pass the resourceName is the test // specified it. When constructing actual and expected file names from this data, // however, we will ensure that the name has the ".sarif" extension. We do this // for test classes such as the Fortify converter that operate again non-SARIF inputs. - string actualSarifText = ConstructTestOutputFromInputResource("Inputs." + resourceName); + string actualSarifText = ConstructTestOutputFromInputResource("Inputs." + inputResourceName); - resourceName = Path.GetFileNameWithoutExtension(resourceName) + ".sarif"; + expectedOutputResourceName = Path.GetFileNameWithoutExtension(expectedOutputResourceName) + ".sarif"; var sb = new StringBuilder(); - string expectedSarifText = GetResourceText("ExpectedOutputs." + resourceName); + string expectedSarifText = GetResourceText("ExpectedOutputs." + expectedOutputResourceName); bool passed; if (_testProducesSarifCurrentVersion) @@ -88,13 +85,13 @@ protected virtual void RunTest(string resourceName) if (!passed) { - string errorMessage = string.Format(@"there should be no unexpected diffs detected comparing actual results to '{0}'.", resourceName); + string errorMessage = string.Format(@"there should be no unexpected diffs detected comparing actual results to '{0}'.", inputResourceName); sb.AppendLine(errorMessage); if (!Utilities.RunningInAppVeyor) { - string expectedFilePath = GetOutputFilePath("ExpectedOutputs", resourceName); - string actualFilePath = GetOutputFilePath("ActualOutputs", resourceName); + string expectedFilePath = GetOutputFilePath("ExpectedOutputs", expectedOutputResourceName); + string actualFilePath = GetOutputFilePath("ActualOutputs", expectedOutputResourceName); string expectedRootDirectory = Path.GetDirectoryName(expectedFilePath); string actualRootDirectory = Path.GetDirectoryName(actualFilePath); @@ -116,7 +113,7 @@ protected virtual void RunTest(string resourceName) // We retrieve all test strings from embedded resources. To rebaseline, we need to // compute the enlistment location from which these resources are compiled. - expectedFilePath = Path.Combine(testDirectory, resourceName); + expectedFilePath = Path.Combine(testDirectory, expectedOutputResourceName); File.WriteAllText(expectedFilePath, actualSarifText); } } diff --git a/src/Sarif.UnitTests/Processors/Log/SarifLogExtensionTests.cs b/src/Sarif.UnitTests/Processors/Log/SarifLogExtensionTests.cs index 083eb362c..f12b83317 100644 --- a/src/Sarif.UnitTests/Processors/Log/SarifLogExtensionTests.cs +++ b/src/Sarif.UnitTests/Processors/Log/SarifLogExtensionTests.cs @@ -78,7 +78,7 @@ public void AbsoluteUri_ReversesRebasedURIs() logs.Add(log); } logs.RebaseUri("SRCROOT", false, new Uri(RandomSarifLogGenerator.GeneratorBaseUri)).MakeUrisAbsolute(); - + // All file URIs should be absolute. logs.All( log => diff --git a/src/Sarif.UnitTests/Sarif.UnitTests.csproj b/src/Sarif.UnitTests/Sarif.UnitTests.csproj index 72d5fdbb6..af3660516 100644 --- a/src/Sarif.UnitTests/Sarif.UnitTests.csproj +++ b/src/Sarif.UnitTests/Sarif.UnitTests.csproj @@ -31,6 +31,15 @@ + + + + + + + + + @@ -88,6 +97,15 @@ + + + + + + + + + diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests.sarif new file mode 100644 index 000000000..e6b1d88f2 --- /dev/null +++ b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests.sarif @@ -0,0 +1,284 @@ +{ + "$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28", + "version": "2.0.0-csd.2.beta.2018-11-28", + "runs": [ + { + "tool": { + "name": "Sarif.UnitTests", + "fullName": "Sarif.UnitTests.1.3.3.0-beta", + "version": "1.3.3.0", + "semanticVersion": "1.3.3", + "sarifLoggerVersion": "1.5.22.0" + }, + "invocations": [ + { + "toolNotifications": [ + { + "message": { + "text": "A notification was raised. Notification kind was: 'tool notification'.", + "messageId": "NotificationMessage", + "arguments": [ + "tool notification" + ] + } + } + ], + "configurationNotifications": [ + { + "message": { + "text": "A notification was raised. Notification kind was: 'configuration notification'.", + "messageId": "NotificationMessage", + "arguments": [ + "configuration notification" + ] + } + } + ] + } + ], + "originalUriBaseIds": { + "TESTROOT": { + "uri": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + } + }, + "files": [ + { + "mimeType": "text/plain", + "contents": { + "binary": "UmVnaW9uX0F0X1N0YXJ0X09mX0ZpbGUgKHRoaXMgaXNuJ3QgcGFydCBvZiB0aGUgcmVnaW9uLi4uKQ0KTW9yZSBjb250ZXh0Lg0KDQpUaGlzIGlzIGEgc2FtcGxlIHRhcmdldCBmaWxlIGZvcg0Kc29tZSBTQVJJRiB0ZXN0aW5nLiBUaGlzIGZpbGUgd2lsbA0KcG90ZW50aWFsbHkgYmUgZW1iZWRkZWQgaW4gU0FSSUYgbG9ncw0KYW5kIHVzZWQgaW4gdmFyaW91cyBJREUgY29udGV4dHMgdG8NCnZlcmlmeSB0aGF0IHZhcmlvdXMgcmVnaW9ucyBhcmUgDQpjb3JyZWN0bHkgY29uc3RydWN0ZWQsIGV0Yy4NCg0KSGVyZSBhcmUgc29tZSBzcGVjaWFsIHZhbHVlcyB0aGF0IHdpbGwgYmUgcmVmZXJlbmNlZCBpbiBmYWJyaWNhdGVkIHJlc3VsdHM6DQoNCkxlYWRpbmcgY29udGV4dC4NCiAgUmVnaW9uX09uZSAodGhpcyBpc24ndCBwYXJ0IG9mIHRoZSByZWdpb24uLi4pDQpUcmFpbGluZyBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQogICAgICAgICBNdWx0aWxpbmVfUmVnaW9uX1BhcnRPbmUNCk11bHRpbGluZV9SZWdpb25fUGFydFR3bw0KQWRkaXRpb25hbCBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQpSZWdpb25fQXRfRW5kX09mX0ZpbGU=" + }, + "hashes": { + "md5": "7650327483BE2466ADC6599198B2989A", + "sha-1": "91655EA8262D81C262A8687E9667AEFF7432906A", + "sha-256": "1BDE85DC91168DAD541E776BB0437AC8A22D2959351A0640F2757D72AEE60C8A" + } + } + ], + "results": [ + { + "ruleId": "TEST2001", + "message": { + "text": "This result is at the beginning of the file and selects 'Region_At_Start_Of_File'.", + "messageId": "MatchAtBeginningOfFile", + "arguments": [ + "Region_At_Start_Of_File" + ] + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", + "uriBaseId": "TESTROOT", + "fileIndex": 0 + }, + "region": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 24, + "charLength": 23, + "snippet": { + "text": "Region_At_Start_Of_File" + } + }, + "contextRegion": { + "startLine": 1, + "startColumn": 1, + "endLine": 2, + "endColumn": 14, + "charLength": 73, + "snippet": { + "text": "Region_At_Start_Of_File (this isn't part of the region...)\r\nMore context." + } + } + } + } + ] + }, + { + "ruleId": "TEST2002", + "message": { + "text": "This result selects a single-line interior region of value 'Region_One'.", + "messageId": "SingleLineInteriorMatch", + "arguments": [ + "Region_One" + ] + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", + "uriBaseId": "TESTROOT", + "fileIndex": 0 + }, + "region": { + "startLine": 14, + "startColumn": 3, + "endLine": 14, + "endColumn": 13, + "charOffset": 387, + "charLength": 10, + "snippet": { + "text": "Region_One" + } + }, + "contextRegion": { + "startLine": 13, + "startColumn": 1, + "endLine": 15, + "endColumn": 18, + "charOffset": 367, + "charLength": 84, + "snippet": { + "text": "Leading context.\r\n Region_One (this isn't part of the region...)\r\nTrailing context." + } + } + } + } + ] + }, + { + "ruleId": "TEST2003", + "message": { + "text": "This results selects a region that crosses multiple lines starting with 'Multiline_Region_Part_one'." + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", + "uriBaseId": "TESTROOT", + "fileIndex": 0 + }, + "region": { + "startLine": 18, + "startColumn": 10, + "endLine": 19, + "endColumn": 25, + "charOffset": 485, + "charLength": 50, + "snippet": { + "text": "Multiline_Region_PartOne\r\nMultiline_Region_PartTwo" + } + }, + "contextRegion": { + "startLine": 17, + "startColumn": 1, + "endLine": 20, + "endColumn": 20, + "charOffset": 455, + "charLength": 101, + "snippet": { + "text": "Additional context.\r\n Multiline_Region_PartOne\r\nMultiline_Region_PartTwo\r\nAdditional context." + } + } + } + } + ] + }, + { + "ruleId": "TEST2004", + "message": { + "text": "This result is at the end of the file and selects 'Region_At_End_Of_File'." + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", + "uriBaseId": "TESTROOT", + "fileIndex": 0 + }, + "region": { + "startLine": 23, + "startColumn": 1, + "endLine": 23, + "endColumn": 22, + "charOffset": 581, + "charLength": 21, + "snippet": { + "text": "Region_At_End_Of_File" + } + }, + "contextRegion": { + "startLine": 22, + "startColumn": 1, + "endLine": 23, + "endColumn": 22, + "charOffset": 560, + "charLength": 42, + "snippet": { + "text": "Additional context.\r\nRegion_At_End_Of_File" + } + } + } + } + ] + }, + { + "ruleId": "TEST2005", + "message": { + "text": "A space between two words was detected.", + "messageId": "GlobalMessage" + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", + "uriBaseId": "TESTROOT", + "fileIndex": 0 + }, + "region": { + "startLine": 15, + "startColumn": 9, + "endLine": 15, + "endColumn": 10, + "charOffset": 442, + "charLength": 1, + "snippet": { + "text": " " + } + }, + "contextRegion": { + "startLine": 14, + "startColumn": 1, + "endLine": 16, + "endColumn": 1, + "charOffset": 385, + "charLength": 68, + "snippet": { + "text": " Region_One (this isn't part of the region...)\r\nTrailing context.\r\n" + } + } + } + } + ] + } + ], + "resources": { + "messageStrings": { + "NotificationMessage": "A notification was raised. Notification kind was: '{0}'.", + "GlobalMessage": "A space between two words was detected." + }, + "rules": { + "TEST2001": { + "id": "TEST2001", + "messageStrings": { + "MatchAtBeginningOfFile": "This result is at the beginning of the file and selects '{0}'." + } + }, + "TEST2002": { + "id": "TEST2002", + "messageStrings": { + "SingleLineInteriorMatch": "This result selects a single-line interior region of value '{0}'." + } + } + } + }, + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_ComprehensiveRegionProperties.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_ComprehensiveRegionProperties.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_ComprehensiveRegionProperties.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_ComprehensiveRegionProperties.sarif diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_ContextRegionSnippets.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_ContextRegionSnippets.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_ContextRegionSnippets.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_ContextRegionSnippets.sarif diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_FlattenedMessages.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_FlattenedMessages.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_FlattenedMessages.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_FlattenedMessages.sarif diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif similarity index 90% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif index 27b577f0e..e6b1d88f2 100644 --- a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif +++ b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes+TextFiles+ComprehensiveRegionProperties+RegionSnippets+ContextRegionSnippets+FlattenedMessages.sarif @@ -1,6 +1,6 @@ { - "$schema": "http://json.schemastore.org/sarif-2.0.0", - "version": "2.0.0", + "$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28", + "version": "2.0.0-csd.2.beta.2018-11-28", "runs": [ { "tool": { @@ -8,8 +8,7 @@ "fullName": "Sarif.UnitTests.1.3.3.0-beta", "version": "1.3.3.0", "semanticVersion": "1.3.3", - "sarifLoggerVersion": "1.5.22.0", - "language": "en-US" + "sarifLoggerVersion": "1.5.22.0" }, "invocations": [ { @@ -38,30 +37,23 @@ } ], "originalUriBaseIds": { - "TESTROOT": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + "TESTROOT": { + "uri": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + } }, - "files": { - "#TESTROOT#InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt": { + "files": [ + { "mimeType": "text/plain", "contents": { "binary": "UmVnaW9uX0F0X1N0YXJ0X09mX0ZpbGUgKHRoaXMgaXNuJ3QgcGFydCBvZiB0aGUgcmVnaW9uLi4uKQ0KTW9yZSBjb250ZXh0Lg0KDQpUaGlzIGlzIGEgc2FtcGxlIHRhcmdldCBmaWxlIGZvcg0Kc29tZSBTQVJJRiB0ZXN0aW5nLiBUaGlzIGZpbGUgd2lsbA0KcG90ZW50aWFsbHkgYmUgZW1iZWRkZWQgaW4gU0FSSUYgbG9ncw0KYW5kIHVzZWQgaW4gdmFyaW91cyBJREUgY29udGV4dHMgdG8NCnZlcmlmeSB0aGF0IHZhcmlvdXMgcmVnaW9ucyBhcmUgDQpjb3JyZWN0bHkgY29uc3RydWN0ZWQsIGV0Yy4NCg0KSGVyZSBhcmUgc29tZSBzcGVjaWFsIHZhbHVlcyB0aGF0IHdpbGwgYmUgcmVmZXJlbmNlZCBpbiBmYWJyaWNhdGVkIHJlc3VsdHM6DQoNCkxlYWRpbmcgY29udGV4dC4NCiAgUmVnaW9uX09uZSAodGhpcyBpc24ndCBwYXJ0IG9mIHRoZSByZWdpb24uLi4pDQpUcmFpbGluZyBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQogICAgICAgICBNdWx0aWxpbmVfUmVnaW9uX1BhcnRPbmUNCk11bHRpbGluZV9SZWdpb25fUGFydFR3bw0KQWRkaXRpb25hbCBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQpSZWdpb25fQXRfRW5kX09mX0ZpbGU=" }, - "hashes": [ - { - "value": "7650327483BE2466ADC6599198B2989A", - "algorithm": "md5" - }, - { - "value": "91655EA8262D81C262A8687E9667AEFF7432906A", - "algorithm": "sha-1" - }, - { - "value": "1BDE85DC91168DAD541E776BB0437AC8A22D2959351A0640F2757D72AEE60C8A", - "algorithm": "sha-256" - } - ] + "hashes": { + "md5": "7650327483BE2466ADC6599198B2989A", + "sha-1": "91655EA8262D81C262A8687E9667AEFF7432906A", + "sha-256": "1BDE85DC91168DAD541E776BB0437AC8A22D2959351A0640F2757D72AEE60C8A" + } } - }, + ], "results": [ { "ruleId": "TEST2001", @@ -77,7 +69,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 1, @@ -117,7 +110,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 14, @@ -155,7 +149,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 18, @@ -193,7 +188,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 23, @@ -232,7 +228,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 15, @@ -280,7 +277,8 @@ } } } - } + }, + "columnKind": "utf16CodeUnits" } ] } \ No newline at end of file diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes+TextFiles.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes+TextFiles.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes+TextFiles.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes+TextFiles.sarif diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes.sarif similarity index 82% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes.sarif index 74b26a442..a211b3986 100644 --- a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_Hashes.sarif +++ b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_Hashes.sarif @@ -1,6 +1,6 @@ { - "$schema": "http://json.schemastore.org/sarif-2.0.0", - "version": "2.0.0", + "$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28", + "version": "2.0.0-csd.2.beta.2018-11-28", "runs": [ { "tool": { @@ -8,8 +8,7 @@ "fullName": "Sarif.UnitTests.1.3.3.0-beta", "version": "1.3.3.0", "semanticVersion": "1.3.3", - "sarifLoggerVersion": "1.5.22.0", - "language": "en-US" + "sarifLoggerVersion": "1.5.22.0" }, "invocations": [ { @@ -36,27 +35,20 @@ } ], "originalUriBaseIds": { - "TESTROOT": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + "TESTROOT": { + "uri": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + } }, - "files": { - "#TESTROOT#InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt": { + "files": [ + { "mimeType": "text/plain", - "hashes": [ - { - "value": "7650327483BE2466ADC6599198B2989A", - "algorithm": "md5" - }, - { - "value": "91655EA8262D81C262A8687E9667AEFF7432906A", - "algorithm": "sha-1" - }, - { - "value": "1BDE85DC91168DAD541E776BB0437AC8A22D2959351A0640F2757D72AEE60C8A", - "algorithm": "sha-256" - } - ] + "hashes": { + "md5": "7650327483BE2466ADC6599198B2989A", + "sha-1": "91655EA8262D81C262A8687E9667AEFF7432906A", + "sha-256": "1BDE85DC91168DAD541E776BB0437AC8A22D2959351A0640F2757D72AEE60C8A" + } } - }, + ], "results": [ { "ruleId": "TEST2001", @@ -71,7 +63,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 1, @@ -95,7 +88,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 14, @@ -116,7 +110,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 18, @@ -137,7 +132,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "charOffset": 581, @@ -157,7 +153,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 15, @@ -188,7 +185,8 @@ } } } - } + }, + "columnKind": "utf16CodeUnits" } ] } \ No newline at end of file diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_RegionSnippets.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_RegionSnippets.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_RegionSnippets.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_RegionSnippets.sarif diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_TextFiles.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_TextFiles.sarif similarity index 88% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_TextFiles.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_TextFiles.sarif index 75e3ed409..dc9eb357d 100644 --- a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests_TextFiles.sarif +++ b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/ExpectedOutputs/CoreTests_TextFiles.sarif @@ -1,6 +1,6 @@ { - "$schema": "http://json.schemastore.org/sarif-2.0.0", - "version": "2.0.0", + "$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28", + "version": "2.0.0-csd.2.beta.2018-11-28", "runs": [ { "tool": { @@ -8,8 +8,7 @@ "fullName": "Sarif.UnitTests.1.3.3.0-beta", "version": "1.3.3.0", "semanticVersion": "1.3.3", - "sarifLoggerVersion": "1.5.22.0", - "language": "en-US" + "sarifLoggerVersion": "1.5.22.0" }, "invocations": [ { @@ -36,16 +35,18 @@ } ], "originalUriBaseIds": { - "TESTROOT": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + "TESTROOT": { + "uri": "file:///REPLACED_AT_TEST_RUNTIME/src/Sarif.UnitTests/TestData/" + } }, - "files": { - "#TESTROOT#InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt": { + "files": [ + { "mimeType": "text/plain", "contents": { "binary": "UmVnaW9uX0F0X1N0YXJ0X09mX0ZpbGUgKHRoaXMgaXNuJ3QgcGFydCBvZiB0aGUgcmVnaW9uLi4uKQ0KTW9yZSBjb250ZXh0Lg0KDQpUaGlzIGlzIGEgc2FtcGxlIHRhcmdldCBmaWxlIGZvcg0Kc29tZSBTQVJJRiB0ZXN0aW5nLiBUaGlzIGZpbGUgd2lsbA0KcG90ZW50aWFsbHkgYmUgZW1iZWRkZWQgaW4gU0FSSUYgbG9ncw0KYW5kIHVzZWQgaW4gdmFyaW91cyBJREUgY29udGV4dHMgdG8NCnZlcmlmeSB0aGF0IHZhcmlvdXMgcmVnaW9ucyBhcmUgDQpjb3JyZWN0bHkgY29uc3RydWN0ZWQsIGV0Yy4NCg0KSGVyZSBhcmUgc29tZSBzcGVjaWFsIHZhbHVlcyB0aGF0IHdpbGwgYmUgcmVmZXJlbmNlZCBpbiBmYWJyaWNhdGVkIHJlc3VsdHM6DQoNCkxlYWRpbmcgY29udGV4dC4NCiAgUmVnaW9uX09uZSAodGhpcyBpc24ndCBwYXJ0IG9mIHRoZSByZWdpb24uLi4pDQpUcmFpbGluZyBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQogICAgICAgICBNdWx0aWxpbmVfUmVnaW9uX1BhcnRPbmUNCk11bHRpbGluZV9SZWdpb25fUGFydFR3bw0KQWRkaXRpb25hbCBjb250ZXh0Lg0KDQpBZGRpdGlvbmFsIGNvbnRleHQuDQpSZWdpb25fQXRfRW5kX09mX0ZpbGU=" } } - }, + ], "results": [ { "ruleId": "TEST2001", @@ -60,7 +61,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 1, @@ -84,7 +86,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 14, @@ -105,7 +108,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 18, @@ -126,7 +130,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "charOffset": 581, @@ -146,7 +151,8 @@ "physicalLocation": { "fileLocation": { "uri": "InsertOptionalDataVisitor/InsertOptionalDataVisitor.txt", - "uriBaseId": "TESTROOT" + "uriBaseId": "TESTROOT", + "fileIndex": 0 }, "region": { "startLine": 15, @@ -177,7 +183,8 @@ } } } - } + }, + "columnKind": "utf16CodeUnits" } ] } \ No newline at end of file diff --git a/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests.sarif b/src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/Inputs/CoreTests.sarif similarity index 100% rename from src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/CoreTests.sarif rename to src/Sarif.UnitTests/TestData/InsertOptionalDataVisitor/Inputs/CoreTests.sarif diff --git a/src/Sarif.UnitTests/TestData/PrereleaseCompatibilityTransformer/ExpectedOutputs/NestedFiles.sarif b/src/Sarif.UnitTests/TestData/PrereleaseCompatibilityTransformer/ExpectedOutputs/NestedFiles.sarif index 5e425cab6..2f95781a3 100644 --- a/src/Sarif.UnitTests/TestData/PrereleaseCompatibilityTransformer/ExpectedOutputs/NestedFiles.sarif +++ b/src/Sarif.UnitTests/TestData/PrereleaseCompatibilityTransformer/ExpectedOutputs/NestedFiles.sarif @@ -46,6 +46,22 @@ "fileIndex": 3 }, "mimeType": "text/plain" + }, + { + "fileLocation": { + "uri": "/archive_two.zip", + "fileIndex": 4 + }, + "parentIndex": 0, + "mimeType": "application/zip" + }, + { + "fileLocation": { + "uri": "/file.txt", + "fileIndex": 5 + }, + "parentIndex": 4, + "mimeType": "text/plain" } ], "results": [ @@ -63,7 +79,7 @@ } }, "properties": { - "k": "file.txt" + "key": "file.txt" } } ] @@ -81,7 +97,7 @@ "uriBaseId": "SUB", "fileIndex": 2, "properties": { - "k": "#SUB#file.txt" + "key": "#SUB#file.txt" } } } @@ -100,7 +116,26 @@ "uri": "/file.txt", "fileIndex": 1, "properties": { - "k": "file://c:/archive_one.zip#/file.txt" + "key": "file://c:/archive_one.zip#/file.txt" + } + } + } + } + ] + }, + { + "ruleId": "C1", + "message": { + "messageId": "a" + }, + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "/archive_two.zip/file.txt", + "fileIndex": 5, + "properties": { + "key": "file://c:/archive_one.zip#/archive_two.zip/file.txt" } } } @@ -120,4 +155,4 @@ "columnKind": "utf16CodeUnits" } ] -} +} \ No newline at end of file diff --git a/src/Sarif.UnitTests/Visitors/InsertOptionalDataVisitorTests.cs b/src/Sarif.UnitTests/Visitors/InsertOptionalDataVisitorTests.cs index 85e28e713..5dcf060a4 100644 --- a/src/Sarif.UnitTests/Visitors/InsertOptionalDataVisitorTests.cs +++ b/src/Sarif.UnitTests/Visitors/InsertOptionalDataVisitorTests.cs @@ -3,10 +3,9 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.Text; using FluentAssertions; +using Microsoft.CodeAnalysis.Sarif.TestUtilities; using Microsoft.CodeAnalysis.Sarif.Writers; using Newtonsoft.Json; using Xunit; @@ -14,127 +13,101 @@ namespace Microsoft.CodeAnalysis.Sarif.Visitors { - public class InsertOptionalDataVisitorTests : FileDiffingTests + + public class InsertOptionalDataVisitorTests : FileDiffingTests, IClassFixture { - // To rebaseline all test files set this value to true and rerun the testa - private static bool s_rebaseline = false; + public class InsertOptionalDataVisitorTestsFixture : DeletesOutputsDirectoryOnClassInitializationFixture { } - public InsertOptionalDataVisitorTests(ITestOutputHelper outputHelper) : base (outputHelper) - { - } + private OptionallyEmittedData _currentOptionallyEmittedData; - [Theory] - [InlineData(OptionallyEmittedData.Hashes)] - [InlineData(OptionallyEmittedData.TextFiles)] - [InlineData(OptionallyEmittedData.RegionSnippets)] - [InlineData(OptionallyEmittedData.FlattenedMessages)] - [InlineData(OptionallyEmittedData.ContextRegionSnippets)] - [InlineData(OptionallyEmittedData.ComprehensiveRegionProperties)] - [InlineData(OptionallyEmittedData.ComprehensiveRegionProperties | OptionallyEmittedData.RegionSnippets | OptionallyEmittedData.TextFiles | OptionallyEmittedData.Hashes | OptionallyEmittedData.ContextRegionSnippets | OptionallyEmittedData.FlattenedMessages)] - public void InsertOptionalDataVisitorTests_InsertsOptionalDataForCommonConditions(OptionallyEmittedData optionallyEmittedData) + public InsertOptionalDataVisitorTests(ITestOutputHelper outputHelper, InsertOptionalDataVisitorTestsFixture fixture) : base (outputHelper) { - string testDirectory = GetTestDirectory("InsertOptionalDataVisitor"); - - string inputFileName = "CoreTests"; - RunTest(testDirectory, inputFileName, optionallyEmittedData); } - private void RunTest(string testDirectory, string inputFileName, OptionallyEmittedData optionallyEmittedData) - { - var sb = new StringBuilder(); + protected override bool RebaselineExpectedResults => false; - string optionsNameSuffix = "_" + NormalizeOptionallyEmittedDataToString(optionallyEmittedData); + protected override string ConstructTestOutputFromInputResource(string inputResourceName) + { + PrereleaseCompatibilityTransformer.UpdateToCurrentVersion( + GetResourceText(inputResourceName), + forceUpdate: false, + formatting: Formatting.Indented, out string transformedLog); - string expectedFileName = inputFileName + optionsNameSuffix + ".sarif"; - string actualFileName = @"Actual\" + inputFileName + optionsNameSuffix + ".sarif"; - inputFileName = inputFileName + ".sarif"; + SarifLog actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(transformedLog, forceUpdate: false, formatting: Formatting.None, out transformedLog); - expectedFileName = Path.Combine(testDirectory, expectedFileName); - actualFileName = Path.Combine(testDirectory, actualFileName); - inputFileName = Path.Combine(testDirectory, inputFileName); + Uri originalUri = actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"].Uri; + string uriString = originalUri.ToString(); - string actualDirectory = Path.GetDirectoryName(actualFileName); - if (!Directory.Exists(actualDirectory)) { Directory.CreateDirectory(actualDirectory); } + // This code rewrites the log persisted URI to match the test environment + string currentDirectory = Environment.CurrentDirectory; + currentDirectory = currentDirectory.Substring(0, currentDirectory.IndexOf(@"\bld\")); + uriString = uriString.Replace("REPLACED_AT_TEST_RUNTIME", currentDirectory); - File.Exists(inputFileName).Should().BeTrue(); + actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new FileLocation { Uri = new Uri(uriString, UriKind.Absolute) }; - SarifLog actualLog; + var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData); + visitor.Visit(actualLog.Runs[0]); - JsonSerializerSettings settings = new JsonSerializerSettings() - { - Formatting = Formatting.Indented - }; + // Restore the remanufactured URI so that file diffing matches + actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new FileLocation { Uri = originalUri }; - try - { - string logText = File.ReadAllText(inputFileName); - actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(logText, forceUpdate: false, formatting: Formatting.None, out logText); - - Uri originalUri = actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"].Uri; - string uriString = originalUri.ToString(); - - // This code rewrites the log persisted URI to match the test environment - string currentDirectory = Environment.CurrentDirectory; - currentDirectory = currentDirectory.Substring(0, currentDirectory.IndexOf(@"\bld\")); - uriString = uriString.Replace("REPLACED_AT_TEST_RUNTIME", currentDirectory); - - actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new FileLocation { Uri = new Uri(uriString, UriKind.Absolute) }; - - var visitor = new InsertOptionalDataVisitor(optionallyEmittedData); - visitor.Visit(actualLog.Runs[0]); - - // Restore the remanufactured URI so that file diffing matches - actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new FileLocation { Uri = originalUri }; - } - catch (Exception ex) - { - sb.AppendFormat(CultureInfo.InvariantCulture, "Unhandled exception processing input '{0}' with the following options: '{1}'.\r\n", inputFileName, optionallyEmittedData); - sb.AppendLine(ex.ToString()); - ValidateResults(sb.ToString()); - return; - } - - string expectedSarif = File.Exists(expectedFileName) ? File.ReadAllText(expectedFileName) : null; - if (expectedSarif != null) - { - PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedSarif, forceUpdate:false, formatting: Formatting.None, out expectedSarif); - } + return JsonConvert.SerializeObject(actualLog, Formatting.Indented); + } - string actualSarif = JsonConvert.SerializeObject(actualLog, settings); - PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(actualSarif, forceUpdate: false, formatting: Formatting.None, out actualSarif); + private void RunTest(string inputResourceName, OptionallyEmittedData optionallyEmittedData) + { + _currentOptionallyEmittedData = optionallyEmittedData; + string expectedOutputResourceName = Path.GetFileNameWithoutExtension(inputResourceName); + expectedOutputResourceName = expectedOutputResourceName + "_" + optionallyEmittedData.ToString().Replace(", ", "+"); + RunTest(inputResourceName, expectedOutputResourceName); + } - if (!AreEquivalentSarifLogs(actualSarif, expectedSarif)) - { - if (s_rebaseline) - { - // We rewrite to test output directory. This allows subsequent tests to - // pass without requiring a rebuild that recopies SARIF test files - File.WriteAllText(expectedFileName, actualSarif); + [Fact] + public void InsertOptionalDataVisitor_PersistsHashes() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.Hashes); + } - string subdirectory = Path.GetFileName(testDirectory); - string productTestDirectory = GetProductTestDataDirectory(subdirectory); - expectedFileName = Path.GetFileName(expectedFileName); - expectedFileName = Path.Combine(productTestDirectory, expectedFileName); + [Fact] + public void InsertOptionalDataVisitor_PersistsTextFiles() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.TextFiles); + } - // We also rewrite the checked in test baselines - File.WriteAllText(expectedFileName, actualSarif); - } - else - { - File.WriteAllText(actualFileName, actualSarif); + [Fact] + public void InsertOptionalDataVisitor_PersistsRegionSnippets() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.RegionSnippets); + } - string errorMessage = "Expanding optional data for input '{0}' produced unexpected results for the following options: '{1}'."; - sb.AppendLine(string.Format(CultureInfo.CurrentCulture, errorMessage, inputFileName, optionallyEmittedData)); + [Fact] + public void InsertOptionalDataVisitor_PersistsFlattenedMessages() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.FlattenedMessages); + } - sb.AppendLine("To compare all difference for this test suite:"); - sb.AppendLine(GenerateDiffCommand("InsertOptionalData", Path.GetDirectoryName(expectedFileName), Path.GetDirectoryName(actualFileName)) + Environment.NewLine); - } - } + [Fact] + public void InsertOptionalDataVisitor_PersistsContextRegionSnippets() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.ContextRegionSnippets); + } - // Add this check to prevent us from unexpectedly checking in this static with the wrong value - s_rebaseline.Should().BeFalse(); + [Fact] + public void InsertOptionalDataVisitor_PersistsComprehensiveRegionProperties() + { + RunTest("CoreTests.sarif", OptionallyEmittedData.ComprehensiveRegionProperties); + } - ValidateResults(sb.ToString()); + [Fact] + public void InsertOptionalDataVisitor_PersistsAll() + { + RunTest("CoreTests.sarif", + OptionallyEmittedData.ComprehensiveRegionProperties | + OptionallyEmittedData.RegionSnippets | + OptionallyEmittedData.TextFiles | + OptionallyEmittedData.Hashes | + OptionallyEmittedData.ContextRegionSnippets | + OptionallyEmittedData.FlattenedMessages); } [Fact] diff --git a/src/Sarif.UnitTests/Visitors/PrereleaseCompatibilityTransformerTests.cs b/src/Sarif.UnitTests/Visitors/PrereleaseCompatibilityTransformerTests.cs index 7f42ffd0c..57dbffe14 100644 --- a/src/Sarif.UnitTests/Visitors/PrereleaseCompatibilityTransformerTests.cs +++ b/src/Sarif.UnitTests/Visitors/PrereleaseCompatibilityTransformerTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT // license. See LICENSE file in the project root for full license information. +using Microsoft.CodeAnalysis.Sarif.TestUtilities; using Microsoft.CodeAnalysis.Sarif.Writers; using Newtonsoft.Json; using Xunit; @@ -8,9 +9,11 @@ namespace Microsoft.CodeAnalysis.Sarif.Visitors { - public class PrereleaseCompatibilityTransformerTests : FileDiffingTests + public class PrereleaseCompatibilityTransformerTests : FileDiffingTests, IClassFixture { - public PrereleaseCompatibilityTransformerTests(ITestOutputHelper outputHelper) : base(outputHelper) { } + public class PrereleaseCompatibilityTransformerTestsFixture : DeletesOutputsDirectoryOnClassInitializationFixture { } + + public PrereleaseCompatibilityTransformerTests(ITestOutputHelper outputHelper) : base (outputHelper){ } protected override bool RebaselineExpectedResults => false; diff --git a/src/Sarif.UnitTests/Visitors/RebaseUriVisitorTests.cs b/src/Sarif.UnitTests/Visitors/RebaseUriVisitorTests.cs index f2dc2847c..48f09ce47 100644 --- a/src/Sarif.UnitTests/Visitors/RebaseUriVisitorTests.cs +++ b/src/Sarif.UnitTests/Visitors/RebaseUriVisitorTests.cs @@ -191,14 +191,6 @@ public void RebaseUriVisitor_VisitFileData_RebasesAllTheThings() string uriRootText = "file:///home/buildAgent/"; string toolsRootBaseId = "TOOLS_ROOT"; - visitor.FileDataParentKeys.Count.Should().Be(4); - visitor.FileDataParentKeys.Where(k => k == null).Count().Should().Be(3); - visitor.FileDataParentKeys.Where(k => k != null && k.StartsWith(uriRootText)).Count().Should().Be(1); - - visitor.FileDataKeys.Count.Should().Be(4); - visitor.FileDataKeys.Where(k => k != null && k.StartsWith(uriRootText)).Count().Should().Be(3); - visitor.FileDataKeys.Where(k => k != null && k.StartsWith("#" + toolsRootBaseId + "#")).Count().Should().Be(1); - int uriCount = 17; visitor.FileLocationUriBaseIds.Count.Should().Be(uriCount); @@ -238,10 +230,6 @@ public void RebaseUriVisitor_VisitFileData_RebasesAllTheThings() private class RebaseVerifyingVisitor : SarifRewritingVisitor { - public RebaseVerifyingVisitor() - { - } - public override FileLocation VisitFileLocation(FileLocation node) { FileLocationUris = FileLocationUris ?? new List(); diff --git a/src/Sarif.UnitTests/Visitors/UpdateIndicesVisitorTests.cs b/src/Sarif.UnitTests/Visitors/UpdateIndicesVisitorTests.cs index b821c7e9f..a1ba9d676 100644 --- a/src/Sarif.UnitTests/Visitors/UpdateIndicesVisitorTests.cs +++ b/src/Sarif.UnitTests/Visitors/UpdateIndicesVisitorTests.cs @@ -59,7 +59,7 @@ public void UpdateIndicesVisitor_RemapsFullyQualifiedogicalLNames() [_remappedFullyQualifiedLogicalName] = remappedIndex }; - var visitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap, fileLocationKeyToIndexMap: null); + var visitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap, fileLocationToIndexMap: null); visitor.VisitResult(result); result.Locations[0].LogicalLocationIndex.Should().Be(remappedIndex); @@ -72,12 +72,12 @@ public void UpdateIndicesVisitor_RemapsFileLocations() var result = _result.DeepClone(); int remappedIndex = 42 * 42; - //var fileLocationToIndexMap = new Dictionary(FileLocation.ValueComparer) - //{ - // [new FileLocation { Uri = _remappedUri, UriBaseId = _remappedUriBaseId }] = remappedIndex - //}; + var fileLocationToIndexMap = new Dictionary() + { + [result.Locations[0].PhysicalLocation.FileLocation] = remappedIndex + }; - var visitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap: null, null); + var visitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap: null, fileLocationToIndexMap: fileLocationToIndexMap); visitor.VisitResult(result); result.Locations[0].LogicalLocationIndex.Should().Be(Int32.MaxValue); diff --git a/src/Sarif.UnitTests/Writers/SarifLoggerTests.cs b/src/Sarif.UnitTests/Writers/SarifLoggerTests.cs index 20494c3f2..3cf0c5350 100644 --- a/src/Sarif.UnitTests/Writers/SarifLoggerTests.cs +++ b/src/Sarif.UnitTests/Writers/SarifLoggerTests.cs @@ -463,7 +463,7 @@ public void SarifLogger_ScrapesFilesFromResult() { string fileName = @"file" + i + ".cpp"; string fileDataKey = "file:///" + fileName; - sarifLog.Runs[0].Files.Where(f => f.FileLocation.Uri.AbsolutePath.Contains(fileDataKey)).Any().Should().BeTrue(); + sarifLog.Runs[0].Files.Where(f => f.FileLocation.Uri.AbsoluteUri.ToString().Contains(fileDataKey)).Any().Should().BeTrue(); } sarifLog.Runs[0].Files.Count.Should().Be(fileCount); diff --git a/src/Sarif/Autogenerated/SarifRewritingVisitor.cs b/src/Sarif/Autogenerated/SarifRewritingVisitor.cs index e322a84bf..17481f05c 100644 --- a/src/Sarif/Autogenerated/SarifRewritingVisitor.cs +++ b/src/Sarif/Autogenerated/SarifRewritingVisitor.cs @@ -701,7 +701,10 @@ public virtual Run VisitRun(Run node) } } - if (node.OriginalUriBaseIds != null) + // OriginalUriBaseIds are directories, not files. We'll disable this visit until the + // schema can catch up with this reality. + // https://github.com/oasis-tcs/sarif-spec/issues/306 + /*if (node.OriginalUriBaseIds != null) { var keys = node.OriginalUriBaseIds.Keys.ToArray(); foreach (var key in keys) @@ -712,7 +715,7 @@ public virtual Run VisitRun(Run node) node.OriginalUriBaseIds[key] = VisitNullChecked(value); } } - } + }*/ if (node.Files != null) { diff --git a/src/Sarif/Core/FileKey.cs b/src/Sarif/Core/FileKey.cs deleted file mode 100644 index 21ba7e218..000000000 --- a/src/Sarif/Core/FileKey.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - -namespace Microsoft.CodeAnalysis.Sarif.Core -{ - public class FileKey - { - public FileKey() - { - ParentIndex = -1; - } - - public Uri Uri; - public string UriBaseId; - public int ParentIndex; - } -} diff --git a/src/Sarif/Core/Run.cs b/src/Sarif/Core/Run.cs index 118514ea1..a6725cc70 100644 --- a/src/Sarif/Core/Run.cs +++ b/src/Sarif/Core/Run.cs @@ -77,6 +77,7 @@ public int GetFileIndex( { if (addToFilesTableIfNotPresent) { + this.Files = this.Files ?? new List(); fileIndex = this.Files.Count; string mimeType = Writers.MimeType.DetermineFromFileExtension(filesTableKey.Uri.ToString()); diff --git a/src/Sarif/NotYetAutoGenerated/SarifRewritingVisitor.cs b/src/Sarif/NotYetAutoGenerated/SarifRewritingVisitor.cs index e322a84bf..17481f05c 100644 --- a/src/Sarif/NotYetAutoGenerated/SarifRewritingVisitor.cs +++ b/src/Sarif/NotYetAutoGenerated/SarifRewritingVisitor.cs @@ -701,7 +701,10 @@ public virtual Run VisitRun(Run node) } } - if (node.OriginalUriBaseIds != null) + // OriginalUriBaseIds are directories, not files. We'll disable this visit until the + // schema can catch up with this reality. + // https://github.com/oasis-tcs/sarif-spec/issues/306 + /*if (node.OriginalUriBaseIds != null) { var keys = node.OriginalUriBaseIds.Keys.ToArray(); foreach (var key in keys) @@ -712,7 +715,7 @@ public virtual Run VisitRun(Run node) node.OriginalUriBaseIds[key] = VisitNullChecked(value); } } - } + }*/ if (node.Files != null) { diff --git a/src/Sarif/Visitors/UpdateIndicesVisitor.cs b/src/Sarif/Visitors/UpdateIndicesVisitor.cs index 890c2d978..eff35a65f 100644 --- a/src/Sarif/Visitors/UpdateIndicesVisitor.cs +++ b/src/Sarif/Visitors/UpdateIndicesVisitor.cs @@ -9,12 +9,12 @@ namespace Microsoft.CodeAnalysis.Sarif.Visitors public class UpdateIndicesVisitor : SarifRewritingVisitor { private IDictionary _fullyQualifiedLogicalNameToIndexMap; - private IDictionary _fileLocationKeyToIndexMap; + private IDictionary _fileLocationToIndexMap; - public UpdateIndicesVisitor(IDictionary fullyQualifiedLogicalNameToIndexMap, IDictionary fileLocationKeyToIndexMap) + public UpdateIndicesVisitor(IDictionary fullyQualifiedLogicalNameToIndexMap, IDictionary fileLocationToIndexMap) { _fullyQualifiedLogicalNameToIndexMap = fullyQualifiedLogicalNameToIndexMap; - _fileLocationKeyToIndexMap = fileLocationKeyToIndexMap; + _fileLocationToIndexMap = fileLocationToIndexMap; } public override Location VisitLocation(Location node) @@ -32,24 +32,11 @@ public override Location VisitLocation(Location node) public override FileLocation VisitFileLocation(FileLocation node) { - - if (_fileLocationKeyToIndexMap != null) + if (_fileLocationToIndexMap != null) { - string key = node.Uri.OriginalString; - - - string uriBaseId = node.UriBaseId; - if (!string.IsNullOrEmpty(uriBaseId)) - { - key = "#" + uriBaseId + "#" + key; - } - - if (_fileLocationKeyToIndexMap.TryGetValue(key, out int index)) + if (_fileLocationToIndexMap.TryGetValue(node, out int index)) { - var fileLocation = FileLocation.CreateFromFilesDictionaryKey(key); - node.Uri = new Uri(UriHelper.MakeValidUri(fileLocation.Uri.OriginalString), UriKind.RelativeOrAbsolute); - node.UriBaseId = fileLocation.UriBaseId; - node.FileIndex = index; + node.FileIndex = index; } } diff --git a/src/Sarif/Writers/PrereleaseCompatibilityTransformer.cs b/src/Sarif/Writers/PrereleaseCompatibilityTransformer.cs index 4010592dd..da304e8e0 100644 --- a/src/Sarif/Writers/PrereleaseCompatibilityTransformer.cs +++ b/src/Sarif/Writers/PrereleaseCompatibilityTransformer.cs @@ -80,7 +80,7 @@ public static SarifLog UpdateToCurrentVersion( { Debug.Assert(modifiedLog == true); transformedSarifLog = JsonConvert.DeserializeObject(sarifLog.ToString()); - var indexUpdatingVisitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap, fileLocationKeyToIndexMap); + var indexUpdatingVisitor = new UpdateIndicesVisitor(fullyQualifiedLogicalNameToIndexMap, null); indexUpdatingVisitor.Visit(transformedSarifLog); updatedLog = JsonConvert.SerializeObject(transformedSarifLog, settings); } diff --git a/src/Sarif/Writers/SarifLogger.cs b/src/Sarif/Writers/SarifLogger.cs index a9e8890d6..56c8b8f21 100644 --- a/src/Sarif/Writers/SarifLogger.cs +++ b/src/Sarif/Writers/SarifLogger.cs @@ -44,7 +44,7 @@ private static Run CreateRun( foreach (string target in analysisTargets) { - Uri uri = new Uri(UriHelper.MakeValidUri(target)); + Uri uri = new Uri(UriHelper.MakeValidUri(target), UriKind.RelativeOrAbsolute); var fileData = FileData.Create( new Uri(target, UriKind.RelativeOrAbsolute), @@ -58,7 +58,7 @@ private static Run CreateRun( fileData.FileLocation = fileLocation; // This call will insert the file object into run.Files if not already present - fileData.FileLocation.FileIndex = run.GetFileIndex(fileData.FileLocation, addToFilesTableIfNotPresent: true); + fileData.FileLocation.FileIndex = run.GetFileIndex(fileData.FileLocation, addToFilesTableIfNotPresent: true, dataToInsert); } }