166 lines
4.1 KiB
C#
166 lines
4.1 KiB
C#
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
// Copyright (c) StellaOps
|
|
|
|
using System.Collections.Immutable;
|
|
using FluentAssertions;
|
|
using StellaOps.Scanner.Emit.Lineage;
|
|
|
|
using StellaOps.TestKit;
|
|
namespace StellaOps.Scanner.Emit.Lineage.Tests;
|
|
|
|
public class SbomLineageTests
|
|
{
|
|
#region SbomId Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomId_New_CreatesUniqueId()
|
|
{
|
|
var id1 = SbomId.New();
|
|
var id2 = SbomId.New();
|
|
|
|
id1.Should().NotBe(id2);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomId_Parse_RoundTrips()
|
|
{
|
|
var original = SbomId.New();
|
|
var parsed = SbomId.Parse(original.ToString());
|
|
|
|
parsed.Should().Be(original);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomId_ToString_ReturnsGuidString()
|
|
{
|
|
var id = SbomId.New();
|
|
var str = id.ToString();
|
|
|
|
Guid.TryParse(str, out _).Should().BeTrue();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SbomLineage Model Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomLineage_RequiredProperties_MustBeSet()
|
|
{
|
|
var lineage = new SbomLineage
|
|
{
|
|
Id = SbomId.New(),
|
|
ImageDigest = "sha256:abc123",
|
|
ContentHash = "sha256:def456",
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
lineage.Id.Should().NotBe(default(SbomId));
|
|
lineage.ImageDigest.Should().Be("sha256:abc123");
|
|
lineage.ContentHash.Should().Be("sha256:def456");
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomLineage_WithParent_TracksLineage()
|
|
{
|
|
var parentId = SbomId.New();
|
|
var childId = SbomId.New();
|
|
|
|
var child = new SbomLineage
|
|
{
|
|
Id = childId,
|
|
ParentId = parentId,
|
|
ImageDigest = "sha256:child",
|
|
ContentHash = "sha256:childhash",
|
|
CreatedAt = DateTimeOffset.UtcNow,
|
|
Ancestors = [parentId]
|
|
};
|
|
|
|
child.ParentId.Should().Be(parentId);
|
|
child.Ancestors.Should().Contain(parentId);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomLineage_WithDiffPointer_TracksChanges()
|
|
{
|
|
var diff = new SbomDiffPointer
|
|
{
|
|
ComponentsAdded = 5,
|
|
ComponentsRemoved = 2,
|
|
ComponentsModified = 3,
|
|
DiffHash = "sha256:diffhash"
|
|
};
|
|
|
|
var lineage = new SbomLineage
|
|
{
|
|
Id = SbomId.New(),
|
|
ParentId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
ContentHash = "sha256:content",
|
|
CreatedAt = DateTimeOffset.UtcNow,
|
|
DiffFromParent = diff
|
|
};
|
|
|
|
lineage.DiffFromParent.Should().NotBeNull();
|
|
lineage.DiffFromParent!.TotalChanges.Should().Be(10);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomLineage_RootLineage_HasNoParent()
|
|
{
|
|
var root = new SbomLineage
|
|
{
|
|
Id = SbomId.New(),
|
|
ImageDigest = "sha256:root",
|
|
ContentHash = "sha256:roothash",
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
root.ParentId.Should().BeNull();
|
|
root.Ancestors.Should().BeEmpty();
|
|
root.DiffFromParent.Should().BeNull();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SbomDiffPointer Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomDiffPointer_TotalChanges_SumsAllCategories()
|
|
{
|
|
var pointer = new SbomDiffPointer
|
|
{
|
|
ComponentsAdded = 10,
|
|
ComponentsRemoved = 5,
|
|
ComponentsModified = 8,
|
|
DiffHash = "sha256:hash"
|
|
};
|
|
|
|
pointer.TotalChanges.Should().Be(23);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void SbomDiffPointer_EmptyDiff_HasZeroChanges()
|
|
{
|
|
var pointer = new SbomDiffPointer
|
|
{
|
|
ComponentsAdded = 0,
|
|
ComponentsRemoved = 0,
|
|
ComponentsModified = 0,
|
|
DiffHash = "sha256:empty"
|
|
};
|
|
|
|
pointer.TotalChanges.Should().Be(0);
|
|
}
|
|
|
|
#endregion
|
|
}
|