Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,31 @@ jobs:
matrix:
options:
- os: ubuntu-latest
framework: net8.0
framework: net11.0
sdk-preview: true
runtime: -x64
codecov: false
- os: macos-latest
framework: net8.0
framework: net11.0
sdk-preview: true
runtime: -x64
codecov: false
- os: windows-latest
framework: net8.0
framework: net11.0
sdk-preview: true
runtime: -x64
codecov: false

- os: ubuntu-latest
framework: net10.0
runtime: -x64
codecov: false
- os: macos-latest
framework: net10.0
runtime: -x64
codecov: false
- os: windows-latest
framework: net10.0
runtime: -x64
codecov: true

Expand Down Expand Up @@ -52,19 +68,45 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-

- name: DotNet Setup
if: ${{ matrix.options.sdk-preview != true }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
10.0.x

- name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v4
with:
dotnet-quality: preview
dotnet-version: |
11.0.x

- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}"

- name: DotNet Build Preview
if: ${{ matrix.options.sdk-preview == true }}
shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}"
env:
SIXLABORS_TESTING_PREVIEW: True

- name: DotNet Test
if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
XUNIT_PATH: .\tests\SharedInfrastructure.Tests # Required for xunit

- name: DotNet Test Preview
if: ${{ matrix.options.sdk-preview == true }}
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
SIXLABORS_TESTING_PREVIEW: True
XUNIT_PATH: .\tests\SharedInfrastructure.Tests # Required for xunit

- name: Update Codecov
Expand Down
18 changes: 18 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Pins the .NET SDK to major version 10 or later for all SixLabors repositories.
// The build copies this file to consuming repositories together with .editorconfig and
// the other shared config files (see msbuild/targets/SixLabors.Src.targets).
{
"sdk": {
// The floor, not an exact build: resolution never selects an SDK below major 10.
"version": "10.0.0",

// Select the newest installed SDK at or above the floor. This spans feature bands,
// minor versions, and major versions, so a machine with only stable 10.0.x SDKs
// resolves the newest of those, and a machine with a newer SDK resolves that instead.
"rollForward": "latestMajor",

// Let the CLI and Visual Studio select preview SDKs when one is installed.
// Machines and CI lanes without a preview SDK are unaffected.
"allowPrerelease": true
}
}
2 changes: 1 addition & 1 deletion msbuild/props/SixLabors.Global.props
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@

<!-- Compilation settings that explicitly differ from the Sdk.props/targets defaults -->
<PropertyGroup>
<LangVersion>12.0</LangVersion>
<LangVersion>14.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Features>strict;IOperation</Features>
<HighEntropyVA>true</HighEntropyVA>
Expand Down
19 changes: 15 additions & 4 deletions msbuild/targets/SixLabors.Src.targets
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,26 @@

<ItemGroup>
<!-- Shared config files that have to exist at root level. -->
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.editorconfig;$(MSBuildThisFileDirectory)..\..\.gitattributes;$(MSBuildThisFileDirectory)..\..\AGENTS.md;$(MSBuildThisFileDirectory)..\..\CLAUDE.md;$(MSBuildThisFileDirectory)..\..\GEMINI.md;$(MSBuildThisFileDirectory)..\..\codecov.yml;" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.editorconfig" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.gitattributes" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\AGENTS.md" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\CLAUDE.md" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\GEMINI.md" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\codecov.yml" />
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\global.json" />
</ItemGroup>

<!-- Copy the config files on src build. -->
<Target Name="SixLaborsCopyConfigFiles" BeforeTargets="Build" Condition="'$(SixLaborsDisableConfigCopy)' == ''">
<Target Name="SixLaborsCopyConfigFiles" BeforeTargets="Build" Condition="'$(SIXLABORS_DISABLE_CONFIG_COPY)' == ''">
<Copy SourceFiles="@(SixLaborsConfigFilesToCopy)"
SkipUnchangedFiles = "true"
DestinationFolder="$(SixLaborsSolutionDirectory)" />

<!--
Copied separately because the file lives in the .github subdirectory. DestinationFolder
above flattens everything into the repo root, so this copy uses DestinationFiles with
the full target path to keep the subpath intact.
-->
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\.github\copilot-instructions.md"
SkipUnchangedFiles="true"
DestinationFiles="$(SixLaborsSolutionDirectory).github\copilot-instructions.md" />
Expand Down Expand Up @@ -67,8 +79,7 @@
and '$(TargetFramework)'!=''
and $([System.String]::Copy('$(PackageId)').StartsWith('SixLabors.'))
and '$(PackageId)'!='SixLabors.Licensing'
and ( '$(PkgSixLabors_Licensing)'==''
or !Exists('$(PkgSixLabors_Licensing)\build\net8.0\SixLabors.Licensing.dll') )">
and ( '$(PkgSixLabors_Licensing)'=='' or !Exists('$(PkgSixLabors_Licensing)\build\net8.0\SixLabors.Licensing.dll') )">
<Error Text="Licensing task not found under $(PkgSixLabors_Licensing)\build\net8.0. Ensure the dev-only PackageReference (GeneratePathProperty='true') is present and restore ran." />
</Target>

Expand Down
45 changes: 3 additions & 42 deletions src/SharedInfrastructure/DebugGuard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal static partial class DebugGuard
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
[Conditional("DEBUG")]
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression("value")] string? parameterName = null)
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
where TValue : class =>
ArgumentNullException.ThrowIfNull(value, parameterName);

Expand All @@ -35,7 +35,7 @@ public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpre
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception>
[Conditional("DEBUG")]
public static void NotNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression("value")] string? paramName = null)
public static void NotNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
ArgumentNullException.ThrowIfNull(value);

Expand Down Expand Up @@ -204,25 +204,6 @@ public static void IsFalse(bool target, string parameterName, string message)
/// </exception>
[Conditional("DEBUG")]
public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength, string parameterName)
{
if (source.Length < minLength)
{
ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
}
}

/// <summary>
/// Verifies, that the `source` span has the length of 'minLength', or longer.
/// </summary>
/// <typeparam name="T">The element type of the spans.</typeparam>
/// <param name="source">The target span.</param>
/// <param name="minLength">The minimum length.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="source"/> has less than <paramref name="minLength"/> items.
/// </exception>
[Conditional("DEBUG")]
public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName)
{
if (source.Length < minLength)
{
Expand All @@ -241,27 +222,7 @@ public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string p
[Conditional("DEBUG")]
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
ReadOnlySpan<TSource> source,
Span<TDest> destination,
string destinationParamName)
{
if (destination.Length < source.Length)
{
ThrowArgumentException($"Destination span is too short!", destinationParamName);
}
}

/// <summary>
/// Verifies that the 'destination' span is not shorter than 'source'.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <typeparam name="TDest">The destination element type.</typeparam>
/// <param name="source">The source span.</param>
/// <param name="destination">The destination span.</param>
/// <param name="destinationParamName">The name of the argument for 'destination'.</param>
[Conditional("DEBUG")]
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
Span<TSource> source,
Span<TDest> destination,
ReadOnlySpan<TDest> destination,
string destinationParamName)
{
if (destination.Length < source.Length)
Expand Down
49 changes: 3 additions & 46 deletions src/SharedInfrastructure/Guard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal static partial class Guard
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNull<TValue>([NotNull]TValue? value, [CallerArgumentExpression("value")] string? parameterName = null)
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
where TValue : class =>
ArgumentNullException.ThrowIfNull(value, parameterName);

Expand All @@ -33,7 +33,7 @@ public static void NotNull<TValue>([NotNull]TValue? value, [CallerArgumentExpres
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNullOrWhiteSpace([NotNull]string? value, string parameterName)
public static void NotNullOrWhiteSpace([NotNull] string? value, string parameterName)
{
if (!string.IsNullOrWhiteSpace(value))
{
Expand Down Expand Up @@ -221,27 +221,6 @@ public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength,
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
}

/// <summary>
/// Verifies, that the `source` span has the length of 'minLength', or longer.
/// </summary>
/// <typeparam name="T">The element type of the spans.</typeparam>
/// <param name="source">The target span.</param>
/// <param name="minLength">The minimum length.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="source"/> has less than <paramref name="minLength"/> items.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName)
{
if (source.Length >= minLength)
{
return;
}

ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
}

/// <summary>
/// Verifies that the 'destination' span is not shorter than 'source'.
/// </summary>
Expand All @@ -253,29 +232,7 @@ public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string p
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
ReadOnlySpan<TSource> source,
Span<TDest> destination,
string destinationParamName)
{
if (destination.Length >= source.Length)
{
return;
}

ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName);
}

/// <summary>
/// Verifies that the 'destination' span is not shorter than 'source'.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <typeparam name="TDest">The destination element type.</typeparam>
/// <param name="source">The source span.</param>
/// <param name="destination">The destination span.</param>
/// <param name="destinationParamName">The name of the argument for 'destination'.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
Span<TSource> source,
Span<TDest> destination,
ReadOnlySpan<TDest> destination,
string destinationParamName)
{
if (destination.Length >= source.Length)
Expand Down
2 changes: 1 addition & 1 deletion tests/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<PropertyGroup>
<!--Disable config copy. This solution only.-->
<SixLaborsDisableConfigCopy>true</SixLaborsDisableConfigCopy>
<SIXLABORS_DISABLE_CONFIG_COPY>true</SIXLABORS_DISABLE_CONFIG_COPY>
</PropertyGroup>

<!-- Import the shared tests .props file -->
Expand Down
10 changes: 5 additions & 5 deletions tests/SharedInfrastructure.Tests/DebugGuardTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace SharedInfrastructure.Tests;

public class DebugGuardTests
{
private class Foo
private sealed class Foo
{
}

Expand All @@ -31,7 +31,7 @@ public void AllStaticMethodsOnOnDebugGuardHaveDEBUGConditional()
[Fact]
public void NotNull_WhenNull_Throws()
{
Foo foo = null;
Foo? foo = null;
Assert.Throws<ArgumentNullException>(() => Guard.NotNull(foo, nameof(foo)));
}

Expand All @@ -48,7 +48,7 @@ public void NotNull_WhenNotNull()
[InlineData(" ", true)]
[InlineData("$", false)]
[InlineData("lol", false)]
public void NotNullOrWhiteSpace(string str, bool shouldThrow)
public void NotNullOrWhiteSpace(string? str, bool shouldThrow)
{
if (shouldThrow)
{
Expand Down Expand Up @@ -205,13 +205,13 @@ public void MustBeGreaterThanOrEqualTo_IsLess_ThrowsNoException()
[InlineData(new int[] { 1, 2 }, 1)]
[InlineData(new int[] { 1, 2 }, 2)]
public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int[] value, int minLength)
=> DebugGuard.MustBeSizedAtLeast<int>(value, minLength, "myParamName");
=> DebugGuard.MustBeSizedAtLeast(value, minLength, "myParamName");

[Fact]
public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
{
ArgumentException exception = Assert.Throws<ArgumentException>(
() => DebugGuard.MustBeSizedAtLeast<int>(new int[] { 1, 2 }, 3, "myParamName"));
static () => DebugGuard.MustBeSizedAtLeast([1, 2], 3, "myParamName"));

Assert.Equal("myParamName", exception.ParamName);
Assert.Contains("The size must be at least 3.", exception.Message);
Expand Down
10 changes: 5 additions & 5 deletions tests/SharedInfrastructure.Tests/GuardTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ namespace SharedInfrastructure.Tests;

public class GuardTests
{
private class Foo
private sealed class Foo
{
}

[Fact]
public void NotNull_WhenNull_Throws()
{
Foo foo = null;
Foo? foo = null;
Assert.Throws<ArgumentNullException>(() => Guard.NotNull(foo, nameof(foo)));
}

Expand All @@ -29,7 +29,7 @@ public void NotNull_WhenNotNull()
[InlineData(" ", true)]
[InlineData("$", false)]
[InlineData("lol", false)]
public void NotNullOrWhiteSpace(string str, bool shouldThrow)
public void NotNullOrWhiteSpace(string? str, bool shouldThrow)
{
if (shouldThrow)
{
Expand Down Expand Up @@ -205,13 +205,13 @@ public void MustBeBetweenOrEqualTo_IsLessOrGreater_ThrowsNoException(int value,
[InlineData(2, 1)]
[InlineData(2, 2)]
public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int valueLength, int minLength)
=> Guard.MustBeSizedAtLeast<int>(new int[valueLength], minLength, "myParamName");
=> Guard.MustBeSizedAtLeast(new int[valueLength], minLength, "myParamName");

[Fact]
public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
{
ArgumentException exception =
Assert.Throws<ArgumentException>(() => Guard.MustBeSizedAtLeast<int>(new int[] { 1, 2 }, 3, "myParamName"));
Assert.Throws<ArgumentException>(() => Guard.MustBeSizedAtLeast([1, 2], 3, "myParamName"));

Assert.Equal("myParamName", exception.ParamName);
Assert.Contains("Spans must be at least of length 3", exception.Message);
Expand Down
Loading
Loading