@cyclonedx/cdxgen
Version:
Creates CycloneDX Software Bill of Materials (SBOM) from source or container image
431 lines (377 loc) • 11 kB
JavaScript
import { assert, describe, it } from "poku";
import {
extractPackageInfoFromHintPath,
extractVersionFromHintPath,
isValidVersion,
} from "./dotnetutils.js";
describe("csproj version extraction tests", () => {
const testCases = [
// Basic package structure tests
[
"..\\packages\\BouncyCastle.Cryptography.2.6.2\\lib\\net461\\BouncyCastle.Cryptography.dll",
"2.6.2",
],
[
"../packages/Newtonsoft.Json.13.0.3/lib/net48/Newtonsoft.Json.dll",
"13.0.3",
],
[
"..\\packages\\EntityFramework.6.4.4\\lib\\net45\\EntityFramework.dll",
"6.4.4",
],
// .nuget packages structure
[
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore\\7.0.10\\lib\\net6.0\\Microsoft.EntityFrameworkCore.dll",
"7.0.10",
],
[
"C:/Users/user/.nuget/packages/System.Text.Json/7.0.3/lib/net6.0/System.Text.Json.dll",
"7.0.3",
],
// UNC paths
[
"\\\\server\\share\\packages\\Newtonsoft.Json.13.0.3\\lib\\net48\\Newtonsoft.Json.dll",
"13.0.3",
],
[
"\\\\network\\packages\\MyCompany.Library.2.1.5\\lib\\net472\\MyCompany.Library.dll",
"2.1.5",
],
// lib directory version extraction
["../lib/4.8.5/System.Data.SqlClient.dll", "4.8.5"],
["C:\\projects\\myapp\\lib\\1.2.3\\MyLibrary.dll", "1.2.3"],
// Pre-release versions
[
"..\\packages\\MyPackage.1.2.3-beta1\\lib\\net48\\MyPackage.dll",
"1.2.3-beta1",
],
[
"../nuget/Some.Package.Name.1.0.0-preview.1/lib/netstandard2.0/Some.Package.Name.dll",
"1.0.0-preview.1",
],
[
"../packages/AwesomeLib.3.2.1-alpha.2/lib/net6.0/AwesomeLib.dll",
"3.2.1-alpha.2",
],
[
"..\\packages\\Test.Package.1.0.0-rc.1.2\\lib\\net48\\Test.Package.dll",
"1.0.0-rc.1.2",
],
// Four-part versions
["../packages/A.B.C.1.2.3.4/lib/net48/A.B.C.dll", "1.2.3.4"],
[
"C:\\packages\\Windows.Library.10.0.19041.1\\lib\\net48\\Windows.Library.dll",
"10.0.19041.1",
],
// Zero versions
["../packages/PackageName.0.0.0.0/lib/net48/Package.dll", "0.0.0.0"],
["..\\packages\\TestLib.0.1.0\\lib\\net48\\TestLib.dll", "0.1.0"],
// Unicode characters in paths
[
"C:\\проекты\\packages\\MyLibrary.1.2.3\\lib\\net48\\MyLibrary.dll",
"1.2.3",
],
["../paquets/МояБиблиотека.2.1.0/lib/net48/МояБиблиотека.dll", "2.1.0"],
["C:\\项目\\packages\\我的库.3.2.1\\lib\\net48\\我的库.dll", "3.2.1"],
["..\\packages\\Tëst.Libräry.1.2.3\\lib\\net48\\Tëst.Libräry.dll", "1.2.3"],
// Complex package names
[
"../packages/Microsoft.AspNet.WebApi.Client.5.2.9/lib/net45/System.Net.Http.Formatting.dll",
"5.2.9",
],
[
"C:\\packages\\System.Collections.Immutable.7.0.0\\lib\\net6.0\\System.Collections.Immutable.dll",
"7.0.0",
],
[
"..\\packages\\runtime.native.System.Data.SqlClient.sni.4.7.0\\runtimes\\win-x64\\native\\sni.dll",
"4.7.0",
],
// Different directory structures
[
"C:\\Users\\user\\.nuget\\packages\\newtonsoft.json\\13.0.3\\lib\\net6.0\\Newtonsoft.Json.dll",
"13.0.3",
],
[
"\\\\server\\share\\.nuget\\packages\\microsoft.extensions.logging\\7.0.0\\lib\\net6.0\\Microsoft.Extensions.Logging.dll",
"7.0.0",
],
// Edge cases with dots in package names
["../packages/A.B.C.D.E.1.2.3/lib/net48/A.B.C.D.E.dll", "1.2.3"],
[
"C:\\packages\\Company.Product.Module.Core.2.5.1\\lib\\net48\\Company.Product.Module.Core.dll",
"2.5.1",
],
// Long version numbers
[
"../packages/TestPackage.123.456.789.999/lib/net48/TestPackage.dll",
"123.456.789.999",
],
// Null and empty cases
[null, null],
["", null],
["invalid/path/without/version.dll", null],
["../packages/invalidpath", null],
// Paths that look like they might have versions but don't
["../my.project/files/version.dll", null],
["C:\\code\\version\\1.0\\MyApp.dll", "1.0"], // This should find 1.0
// Mixed case paths
[
"C:\\Packages\\NEWTONSOFT.JSON.13.0.3\\lib\\net48\\Newtonsoft.Json.dll",
"13.0.3",
],
[
"..\\PACKAGES\\EntityFramework.6.4.4\\lib\\net45\\EntityFramework.dll",
"6.4.4",
],
// Very long paths
[
"C:\\very\\long\\path\\with\\many\\directories\\packages\\MyVeryLongPackageName.9.9.9\\lib\\net6.0\\MyVeryLongPackageName.dll",
"9.9.9",
],
// Special characters in package names
[
"../packages/My-Package_With.Symbols.1.2.3/lib/net48/My-Package_With.Symbols.dll",
"1.2.3",
],
["C:\\packages\\Test+Package.4.5.6\\lib\\net48\\Test+Package.dll", "4.5.6"],
// Nested package structures
[
"C:\\Users\\user\\.nuget\\packages\\microsoft\\aspnetcore\\mvc\\2.2.0\\lib\\netstandard2.0\\Microsoft.AspNetCore.Mvc.dll",
"2.2.0",
],
// Build metadata versions (less common but possible)
[
"../packages/MyLib.1.0.0+build.123/lib/net48/MyLib.dll",
"1.0.0+build.123",
],
];
testCases.forEach((testCase, index) => {
it(`should extract version correctly for test case ${index}`, () => {
const version = extractVersionFromHintPath(testCase[0]);
assert.deepStrictEqual(version, testCase[1]);
});
});
});
describe("csproj package info extraction tests", () => {
const packageInfoTestCases = [
// Basic package structure tests
[
"..\\packages\\BouncyCastle.Cryptography.2.6.2\\lib\\net461\\BouncyCastle.Cryptography.dll",
"BouncyCastle.Cryptography",
"2.6.2",
],
[
"../packages/Newtonsoft.Json.13.0.3/lib/net48/Newtonsoft.Json.dll",
"Newtonsoft.Json",
"13.0.3",
],
[
"..\\packages\\EntityFramework.6.4.4\\lib\\net45\\EntityFramework.dll",
"EntityFramework",
"6.4.4",
],
// .nuget packages structure
[
"C:\\Users\\user\\.nuget\\packages\\microsoft.entityframeworkcore\\7.0.10\\lib\\net6.0\\Microsoft.EntityFrameworkCore.dll",
"microsoft.entityframeworkcore",
"7.0.10",
],
// UNC paths
[
"\\\\server\\share\\packages\\Newtonsoft.Json.13.0.3\\lib\\net48\\Newtonsoft.Json.dll",
"Newtonsoft.Json",
"13.0.3",
],
// Pre-release versions
[
"..\\packages\\MyPackage.1.2.3-beta1\\lib\\net48\\MyPackage.dll",
"MyPackage",
"1.2.3-beta1",
],
// Unicode characters
[
"C:\\проекты\\packages\\MyLibrary.1.2.3\\lib\\net48\\MyLibrary.dll",
"MyLibrary",
"1.2.3",
],
// Complex cases
[
"C:\\Users\\user\\.nuget\\packages\\microsoft.aspnetcore.mvc\\2.2.0\\lib\\netstandard2.0\\Microsoft.AspNetCore.Mvc.dll",
"microsoft.aspnetcore.mvc",
"2.2.0",
],
// Edge cases
[null, null, null],
["", null, null],
["invalid/path/without/version.dll", null, null],
];
packageInfoTestCases.forEach((testCase, index) => {
it(`should extract package info correctly for test case ${index}`, () => {
const result = extractPackageInfoFromHintPath(testCase[0]);
assert.deepStrictEqual(result.name, testCase[1]);
assert.deepStrictEqual(result.version, testCase[2]);
});
});
});
describe("version validation tests", () => {
const validVersions = [
// Standard versions
"1.0.0",
"2.6.2",
"13.0.3",
"6.4.4",
"7.0.10",
"4.8.5",
"1.2.3",
"0.0.0",
"999.999.999",
// Two-part versions
"1.0",
"2.5",
"13.0",
// Three-part versions
"1.2.3",
"10.20.30",
"0.0.1",
// Four-part versions
"1.2.3.4",
"10.0.19041.1",
"123.456.789.999",
// Pre-release versions
"1.0.0-alpha",
"1.0.0-beta1",
"2.6.2-rc1",
"13.0.3-preview.1",
"1.2.3-beta.2",
"1.0.0-rc.1.2",
"3.2.1-alpha.2",
"1.0.0-SNAPSHOT",
// Versions with dots and hyphens in pre-release
"1.0.0-feature-branch",
"2.0.0-hotfix.1",
"1.5.0-release-candidate.1",
// Single digit versions
"1.0.0",
"2.0.0",
"0.1.0",
"0.0.1",
];
const invalidVersions = [
// Null and undefined
null,
undefined,
// Empty and whitespace
"",
" ",
" ",
// Invalid formats
"version1.0.0",
"1.0.0version",
"v1.0.0",
"V2.0.0",
// Missing parts
".",
"..",
"1.",
"1.2.",
".1.2",
".1.2.3",
// Non-numeric parts (except pre-release)
"a.b.c",
"1.a.3",
"1.2.b",
"1.2.3.4.5", // Too many parts
// Invalid characters
"1.0.0@",
"1.0.0#",
"1.0.0$",
"1.0.0%",
"1.0.0^",
"1.0.0&",
"1.0.0*",
"1.0.0(",
"1.0.0)",
"1.0.0[",
"1.0.0]",
"1.0.0{",
"1.0.0}",
"1.0.0|",
"1.0.0\\",
"1.0.0/",
"1.0.0<",
"1.0.0>",
"1.0.0?",
// Negative numbers
"-1.0.0",
"1.-2.3",
"1.2.-3",
// Spaces
"1. 0.0",
"1.0 .0",
"1.0. 0",
" 1.0.0",
"1.0.0 ",
// Multiple dots
"1..0.0",
"1.0..0",
"1.0.0.",
"..1.0.0",
// Letters mixed with numbers
"1a.0.0",
"1.0b.0",
"1.0.0c",
// Special edge cases
"latest",
"stable",
"current",
"dev",
"master",
"main",
"HEAD",
// Malformed pre-release
"1.0.0-",
"1.0.0--",
"1.0.0-alpha--beta",
"1.0.0-.",
"1.0.0-.alpha",
];
it("should validate valid versions", () => {
validVersions.forEach((version, index) => {
assert.deepStrictEqual(
isValidVersion(version),
true,
`Failed for valid version: ${version} at index ${index}`,
);
});
});
it("should reject invalid versions", () => {
invalidVersions.forEach((version, index) => {
assert.deepStrictEqual(
isValidVersion(version),
false,
`Failed for invalid version: ${version} at index ${index}`,
);
});
});
});
// Additional specific tests
describe("additional version validation tests", () => {
it("should handle string representations of valid versions", () => {
assert.deepStrictEqual(isValidVersion("1.0.0"), true);
assert.deepStrictEqual(isValidVersion(String("2.6.2")), true);
});
it("should reject non-string inputs", () => {
assert.deepStrictEqual(isValidVersion(123), false);
assert.deepStrictEqual(isValidVersion({}), false);
assert.deepStrictEqual(isValidVersion([]), false);
assert.deepStrictEqual(isValidVersion(true), false);
assert.deepStrictEqual(isValidVersion(false), false);
});
it("should handle boundary cases", () => {
assert.deepStrictEqual(isValidVersion("0.0.0.0"), true); // Four zeros
assert.deepStrictEqual(isValidVersion("999999.999999.999999"), true); // Large numbers
assert.deepStrictEqual(isValidVersion("1.0.0-"), false); // Empty pre-release
assert.deepStrictEqual(isValidVersion("1.0.0-a"), true); // Single char pre-release
});
});