< Summary

Information
Class: Elsa.Bpmn.Interchange.Services.BpmnContentHash
Assembly: Elsa.Bpmn.Interchange
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Bpmn.Interchange/Services/BpmnContentHash.cs
Line coverage
100%
Covered lines: 15
Uncovered lines: 0
Coverable lines: 15
Total lines: 47
Line coverage: 100%
Branch coverage
100%
Covered branches: 2
Total branches: 2
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
OfGraph(...)100%11100%
AppendField(...)100%22100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Bpmn.Interchange/Services/BpmnContentHash.cs

#LineLine coverage
 1using System.Buffers.Binary;
 2using System.Security.Cryptography;
 3using System.Text;
 4
 5namespace Elsa.Bpmn.Interchange.Services;
 6
 7/// <summary>
 8/// The one place a workflow definition's serialized activity graph
 9/// (<see cref="Elsa.Workflows.Management.Entities.WorkflowDefinition.StringData"/>) is turned into a content hash,
 10/// shared by <see cref="BpmnInterchangeDocumentService"/> — which records the hash at import time under
 11/// <see cref="BpmnInterchangeDocumentService.SourceGraphHashCustomPropertyKey"/> to tell a designer-edited graph
 12/// apart from the one BPMN source was imported against — and
 13/// <see cref="Elsa.Bpmn.Interchange.Endpoints.Bpmn.Document.BpmnDocumentETag"/>, so the two never disagree about how
 14/// the same field hashes.
 15/// </summary>
 16internal static class BpmnContentHash
 17{
 18    /// <summary>The hex-encoded SHA-256 of a workflow definition's serialized activity graph.</summary>
 19    public static string OfGraph(string? stringData)
 20    {
 21621        using var hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
 21622        AppendField(hash, stringData);
 21623        return Convert.ToHexString(hash.GetHashAndReset());
 21624    }
 25
 26    /// <summary>
 27    /// Appends a length-prefixed UTF-8 encoding of <paramref name="value"/> to <paramref name="hash"/>, marking a
 28    /// <c>null</c> value distinctly from an empty one so no two different inputs feed the hash the same bytes.
 29    /// </summary>
 30    public static void AppendField(IncrementalHash hash, string? value)
 31    {
 85632        Span<byte> header = stackalloc byte[5];
 33
 85634        if (value is null)
 35        {
 136            header[0] = 0;
 137            hash.AppendData(header[..1]);
 138            return;
 39        }
 40
 85541        var bytes = Encoding.UTF8.GetBytes(value);
 85542        header[0] = 1;
 85543        BinaryPrimitives.WriteInt32BigEndian(header[1..], bytes.Length);
 85544        hash.AppendData(header);
 85545        hash.AppendData(bytes);
 85546    }
 47}