Skip to content

Commit 48571b6

Browse files
authored
Introduce C++ SDK component type (#1599) (#1626)
* Introduce C++ SDK component type
1 parent 74a7efc commit 48571b6

File tree

5 files changed

+159
-0
lines changed

5 files changed

+159
-0
lines changed

src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentMapping.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ internal static class TypedComponentMapping
3636
{ nameof(ComponentType.Spdx), typeof(SpdxComponent) },
3737
{ nameof(ComponentType.DotNet), typeof(DotNetComponent) },
3838
{ nameof(ComponentType.Swift), typeof(SwiftComponent) },
39+
{ nameof(ComponentType.CppSdk), typeof(CppSdkComponent) },
3940
};
4041

4142
/// <summary>

src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,7 @@ public enum ComponentType : byte
6464

6565
[EnumMember]
6666
DotNet = 19,
67+
68+
[EnumMember]
69+
CppSdk = 20,
6770
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#nullable disable
2+
namespace Microsoft.ComponentDetection.Contracts.TypedComponent;
3+
4+
using System.Collections.Generic;
5+
using System.Text.Json.Serialization;
6+
using PackageUrl;
7+
8+
/// <summary>
9+
/// Represents a C++ SDK component.
10+
/// </summary>
11+
public class CppSdkComponent : TypedComponent
12+
{
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="CppSdkComponent"/> class.
15+
/// </summary>
16+
public CppSdkComponent()
17+
{
18+
/* Reserved for deserialization */
19+
}
20+
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="CppSdkComponent"/> class.
23+
/// </summary>
24+
/// <param name="name">The name of the component.</param>
25+
/// <param name="version">The version of the component.</param>
26+
public CppSdkComponent(string name, string version)
27+
{
28+
this.Name = this.ValidateRequiredInput(name, nameof(this.Name), nameof(ComponentType.CppSdk));
29+
this.Version = this.ValidateRequiredInput(version, nameof(this.Version), nameof(ComponentType.CppSdk));
30+
}
31+
32+
[JsonPropertyName("name")]
33+
public string Name { get; set; }
34+
35+
[JsonPropertyName("version")]
36+
public string Version { get; set; }
37+
38+
[JsonIgnore]
39+
public override ComponentType Type => ComponentType.CppSdk;
40+
41+
[JsonPropertyName("packageUrl")]
42+
public override PackageURL PackageUrl
43+
{
44+
get
45+
{
46+
var qualifiers = new SortedDictionary<string, string>
47+
{
48+
{ "type", "cppsdk" },
49+
};
50+
return new PackageURL("generic", null, this.Name, this.Version, qualifiers, null);
51+
}
52+
}
53+
54+
protected override string ComputeId() => $"{this.Name} {this.Version} - {this.Type}";
55+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#nullable disable
2+
namespace Microsoft.ComponentDetection.Contracts.Tests;
3+
4+
using System;
5+
using AwesomeAssertions;
6+
using Microsoft.ComponentDetection.Contracts.TypedComponent;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
9+
[TestClass]
10+
[TestCategory("Governance/All")]
11+
[TestCategory("Governance/ComponentDetection")]
12+
public class CppSdkComponentTests
13+
{
14+
[TestMethod]
15+
public void Constructor_ShouldInitializeProperties()
16+
{
17+
var name = "AwesomeCppLibrary";
18+
var version = "1.2.3";
19+
20+
var component = new CppSdkComponent(name, version);
21+
22+
component.Name.Should().Be(name);
23+
component.Version.Should().Be(version);
24+
component.Type.Should().Be(ComponentType.CppSdk);
25+
component.Id.Should().Be($"{name} {version} - {component.Type}");
26+
}
27+
28+
[TestMethod]
29+
public void Constructor_ShouldThrowException_WhenNameIsNull()
30+
{
31+
Action action = () => new CppSdkComponent(null, "1.2.3");
32+
action.Should().Throw<ArgumentException>().WithMessage("*Name*");
33+
}
34+
35+
[TestMethod]
36+
public void Constructor_ShouldThrowException_WhenNameIsWhitespace()
37+
{
38+
Action action = () => new CppSdkComponent(" ", "1.2.3");
39+
action.Should().Throw<ArgumentException>().WithMessage("*Name*");
40+
}
41+
42+
[TestMethod]
43+
public void Constructor_ShouldThrowException_WhenNameIsEmpty()
44+
{
45+
Action action = () => new CppSdkComponent(string.Empty, "1.2.3");
46+
action.Should().Throw<ArgumentException>().WithMessage("*Name*");
47+
}
48+
49+
[TestMethod]
50+
public void Constructor_ShouldThrowException_WhenVersionIsNull()
51+
{
52+
Action action = () => new CppSdkComponent("AwesomeCppLibrary", null);
53+
action.Should().Throw<ArgumentException>().WithMessage("*Version*");
54+
}
55+
56+
[TestMethod]
57+
public void Constructor_ShouldThrowException_WhenVersionIsWhitespace()
58+
{
59+
Action action = () => new CppSdkComponent("AwesomeCppLibrary", " ");
60+
action.Should().Throw<ArgumentException>().WithMessage("*Version*");
61+
}
62+
63+
[TestMethod]
64+
public void Constructor_ShouldThrowException_WhenVersionIsEmpty()
65+
{
66+
Action action = () => new CppSdkComponent("AwesomeCppLibrary", string.Empty);
67+
action.Should().Throw<ArgumentException>().WithMessage("*Version*");
68+
}
69+
70+
[TestMethod]
71+
public void PackageUrl_ShouldReturnCorrectFormat()
72+
{
73+
var name = "AwesomeCppLibrary";
74+
var version = "1.2.3";
75+
var component = new CppSdkComponent(name, version);
76+
77+
var packageUrl = component.PackageUrl;
78+
79+
packageUrl.Type.Should().Be("generic");
80+
#pragma warning disable CA1308 // PackageURL normalizes to lowercase
81+
packageUrl.Name.Should().Be(name.ToLowerInvariant());
82+
#pragma warning restore CA1308
83+
packageUrl.Version.Should().Be(version);
84+
packageUrl.Namespace.Should().BeNull();
85+
packageUrl.Qualifiers.Should().ContainKey("type");
86+
packageUrl.Qualifiers["type"].Should().Be("cppsdk");
87+
}
88+
}

test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,16 @@ public void TypedComponentMapping_TryGetType_WhitespaceDiscriminator_ReturnsFals
346346
result.Should().BeFalse("TryGetType should return false for whitespace-only discriminator");
347347
targetType.Should().BeNull("targetType should be null for whitespace-only discriminator");
348348
}
349+
350+
[TestMethod]
351+
public void TypedComponent_Serialization_CppSdk()
352+
{
353+
TypedComponent tc = new CppSdkComponent("SomeCppSdk", "1.2.3");
354+
var result = JsonSerializer.Serialize(tc);
355+
var deserializedTC = JsonSerializer.Deserialize<TypedComponent>(result);
356+
deserializedTC.Should().BeOfType(typeof(CppSdkComponent));
357+
var cppSdkComponent = (CppSdkComponent)deserializedTC;
358+
cppSdkComponent.Name.Should().Be("SomeCppSdk");
359+
cppSdkComponent.Version.Should().Be("1.2.3");
360+
}
349361
}

0 commit comments

Comments
 (0)