Skip to content

Commit

Permalink
Add protobuf deserialization tests
Browse files Browse the repository at this point in the history
Signed-off-by: andreas hilti <[email protected]>
  • Loading branch information
andreas-hilti committed Sep 15, 2024
1 parent 1ab1cc2 commit 88c92e5
Show file tree
Hide file tree
Showing 46 changed files with 7,012 additions and 5 deletions.
10 changes: 9 additions & 1 deletion tests/CycloneDX.Core.Tests/Protobuf/ProtocResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@
// Copyright (c) OWASP Foundation. All Rights Reserved.

using System;
using System.IO;

namespace CycloneDX.Core.Tests.Protobuf
{
public class ProtocResult
public class ProtocTextResult
{
public string Output { get; set; }
public string Errors { get; set; }
public int ExitCode { get; set; }
}

public class ProtocBinaryResult
{
public Stream Output { get; set; }
public string Errors { get; set; }
public int ExitCode { get; set; }
}
}
97 changes: 93 additions & 4 deletions tests/CycloneDX.Core.Tests/Protobuf/ProtocRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace CycloneDX.Core.Tests.Protobuf
{
public class ProtocRunner
{
internal ProtocResult Run(string workingDirectory, byte[] input, string[] arguments)
internal ProtocTextResult Run(string workingDirectory, byte[] input, string[] arguments)
{
var protocFilename = "protoc";

Expand Down Expand Up @@ -77,7 +77,7 @@ internal ProtocResult Run(string workingDirectory, byte[] input, string[] argume
{
p.Kill();

return new ProtocResult
return new ProtocTextResult
{
Output = output.ToString(),
Errors = errors.ToString(),
Expand All @@ -87,7 +87,7 @@ internal ProtocResult Run(string workingDirectory, byte[] input, string[] argume

Task.WaitAll(outputTask, errorTask);

return new ProtocResult
return new ProtocTextResult
{
Output = output.ToString(),
Errors = errors.ToString(),
Expand All @@ -96,7 +96,7 @@ internal ProtocResult Run(string workingDirectory, byte[] input, string[] argume
}
catch
{
return new ProtocResult
return new ProtocTextResult
{
Output = "",
Errors = "Unable to execute protoc, ensure you have the protobuf compiler installed",
Expand All @@ -109,6 +109,88 @@ internal ProtocResult Run(string workingDirectory, byte[] input, string[] argume
}
}

internal ProtocBinaryResult Run(string workingDirectory, string input, string[] arguments)
{
var protocFilename = "protoc";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var enviromentPath = Environment.GetEnvironmentVariable("PATH");
var paths = enviromentPath.Split(';');
foreach (var path in paths)
{
var filename = Path.Combine(path, "protoc.exe");
if (File.Exists(filename))
{
protocFilename = filename;
break;
}
}
}

var psi = new ProcessStartInfo(protocFilename, string.Join(" ", arguments))
{
WorkingDirectory = workingDirectory,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};

var p = new Process();
try
{
p.StartInfo = psi;
p.Start();

var output = new MemoryStream();
var errors = new StringBuilder();
var outputTask = ConsumeStreamAsync(p.StandardOutput.BaseStream, output);
var errorTask = ConsumeStreamReaderAsync(p.StandardError, errors);

p.StandardInput.Write(input);
p.StandardInput.Close();

var processExited = p.WaitForExit(20000);

if (processExited == false)
{
p.Kill();

return new ProtocBinaryResult
{
Output = output,
Errors = errors.ToString(),
ExitCode = -1
};
}

Task.WaitAll(outputTask, errorTask);

return new ProtocBinaryResult
{
Output = output,
Errors = errors.ToString(),
ExitCode = p.ExitCode
};
}
catch
{
return new ProtocBinaryResult
{
Output = null,
Errors = "Unable to execute protoc, ensure you have the protobuf compiler installed",
ExitCode = -1
};
}
finally
{
p.Dispose();
}
}


private static async Task ConsumeStreamReaderAsync(StreamReader reader, StringBuilder lines)
{
await Task.Yield();
Expand All @@ -119,5 +201,12 @@ private static async Task ConsumeStreamReaderAsync(StreamReader reader, StringBu
lines.AppendLine(line);
}
}

private static async Task ConsumeStreamAsync(Stream reader, Stream output)
{
await Task.Yield();

reader.CopyTo(output);
}
}
}
113 changes: 113 additions & 0 deletions tests/CycloneDX.Core.Tests/Protobuf/v1.6/SerializationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// This file is part of CycloneDX Library for .NET
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an “AS IS” BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) OWASP Foundation. All Rights Reserved.

using System;
using System.IO;
using Snapshooter;
using Snapshooter.Xunit;
using Xunit;
using Xunit.Abstractions;

namespace CycloneDX.Core.Tests.Protobuf.v1_6
{
[Collection("Protoc Serialization")]
public class SerializationTests
{
private readonly ITestOutputHelper output;

public SerializationTests(ITestOutputHelper output)
{
this.output = output;
}

// I can't be bothered setting up protoc in the github workflow for all platforms
// if anyone wants to have a crack at it please go for it
[LinuxOnlyForCITheory]
[InlineData("valid-annotation-1.6.textproto")]
[InlineData("valid-assembly-1.6.textproto")]
[InlineData("valid-attestation-1.6.textproto")]
[InlineData("valid-bom-1.6.textproto")]
[InlineData("valid-component-hashes-1.6.textproto")]
[InlineData("valid-component-identifiers-1.6.textproto")]
[InlineData("valid-component-ref-1.6.textproto")]
[InlineData("valid-component-swid-1.6.textproto")]
[InlineData("valid-component-swid-full-1.6.textproto")]
[InlineData("valid-component-types-1.6.textproto")]
[InlineData("valid-compositions-1.6.textproto")]
[InlineData("valid-cryptography-full-1.6.textproto")]
[InlineData("valid-cryptography-implementation-1.6.textproto")]
[InlineData("valid-dependency-1.6.textproto")]
[InlineData("valid-empty-components-1.6.textproto")]
[InlineData("valid-evidence-1.6.textproto")]
[InlineData("valid-external-reference-1.6.textproto")]
[InlineData("valid-formulation-1.6.textproto")]
[InlineData("valid-license-expression-1.6.textproto")]
[InlineData("valid-license-id-1.6.textproto")]
[InlineData("valid-license-licensing-1.6.textproto")]
[InlineData("valid-license-name-1.6.textproto")]
[InlineData("valid-machine-learning-1.6.textproto")]
[InlineData("valid-machine-learning-considerations-env-1.6.textproto")]
[InlineData("valid-metadata-author-1.6.textproto")]
[InlineData("valid-metadata-license-1.6.textproto")]
[InlineData("valid-metadata-lifecycle-1.6.textproto")]
[InlineData("valid-metadata-manufacture-1.6.textproto")]
[InlineData("valid-metadata-manufacturer-1.6.textproto")]
[InlineData("valid-metadata-supplier-1.6.textproto")]
[InlineData("valid-metadata-timestamp-1.6.textproto")]
[InlineData("valid-metadata-tool-1.6.textproto")]
[InlineData("valid-metadata-tool-deprecated-1.6.textproto")]
[InlineData("valid-minimal-viable-1.6.textproto")]
[InlineData("valid-patch-1.6.textproto")]
[InlineData("valid-properties-1.6.textproto")]
[InlineData("valid-release-notes-1.6.textproto")]
[InlineData("valid-saasbom-1.6.textproto")]
[InlineData("valid-service-1.6.textproto")]
[InlineData("valid-service-empty-objects-1.6.textproto")]
[InlineData("valid-standard-1.6.textproto")]
[InlineData("valid-tags-1.6.textproto")]
[InlineData("valid-vulnerability-1.6.textproto")]
public void ProtobufDeserializationTest(string filename)
{
using (var tempDir = new CycloneDX.Core.Tests.Protobuf.TempDirectoryWithProtoSchemas())
{
var protobufResourceFilename = Path.Join("Resources", "v1.6", filename);
var protobufTextString = File.ReadAllText(protobufResourceFilename);

var runner = new ProtocRunner();
var result = runner.Run(tempDir.DirectoryPath, protobufTextString, new string[]
{
"--proto_path=./",
"--encode=cyclonedx.v1_6.Bom",
"bom-1.6.proto"
});

if (result.ExitCode == 0)
{
result.Output.Seek(0, SeekOrigin.Begin);
var bom = CycloneDX.Protobuf.Serializer.Deserialize(result.Output);

Snapshot.Match(bom, SnapshotNameExtension.Create(filename));
}
else
{
output.WriteLine(result.Errors);
Assert.Equal(0, result.ExitCode);
}
}
}
}
}
Loading

0 comments on commit 88c92e5

Please sign in to comment.