Skip to main content

lengthIsExact

Short summary

This assertion method checks if the current string stringToCheck length is equal to expectedLength. Processed strings must be in UTF-8 encoding

Attention: All strings are handled as null-terminated byte streams

Parameters

NameTypeCommentKind
stringToCheckPOINTER TO BYTEcurrent string to checkinput
expectedLengthUDINTexpected length of stringToCheckinput
stringLengthUnitUnicodeStringLengthUnitstring length units of measurementinput
messageAssertMessagemessage if the assertion is falseinput

Code

Declaration

METHOD lengthIsExact
VAR_INPUT
(* current string to check *)
stringToCheck :POINTER TO BYTE;
(* expected length of ``stringToCheck`` *)
expectedLength :UDINT;
(* string length units of measurement *)
stringLengthUnit :UnicodeStringLengthUnit;
(* message if the assertion is false *)
message :AssertMessage;
END_VAR
VAR
(* length of current string to check in bytes *)
stringToCheckByteCount :UDINT;
(* length of current string to check in characters *)
stringToCheckCodePointCount :UDINT;

normalizedStringBuffer :POINTER TO BYTE;
bufferSize :UDINT;
normalizedLength :UDINT;
width :DINT;
visibleCharacters :UDINT := 0;
END_VAR
VAR CONSTANT
(*After decomposition one codepoint can extend up to 4 codepoints*)
NORMALIZATION_FACTOR :UDINT := 4;
END_VAR

Implementation

CNM_UnicodeUtilities.GetUtf8StringLength(
stringToCheck,
byteCount => stringToCheckByteCount,
characterCount => stringToCheckCodePointCount
);

// check if string is empty
IF (stringToCheckByteCount = 0) THEN
IF (expectedLength <> 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF
RETURN;
END_IF

CASE (stringLengthUnit) OF
UnicodeStringLengthUnit.BYTES:
IF (stringToCheckByteCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS:
IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS_NFC:
// string size cant increase with NFC
normalizedStringBuffer := __NEW(BYTE, (stringToCheckByteCount+1));
IF normalizedStringBuffer = 0 THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('lengthIsExact, malloc failed'));
RETURN;
END_IF
bufferSize := stringToCheckByteCount + 1; // stringsize + NULL terminator

CNM_UnicodeUtilities.NormalizeUtf8String(
utf8StringBuffer := stringToCheck,
normalForm := CNM_UnicodeUtilities.NormalizationForm.NFC,
normalizedStringBuffer := normalizedStringBuffer,
bufferSize := bufferSize,
normalizedStringLength => normalizedLength
);

CNM_UnicodeUtilities.GetUtf8StringLength(
stringAddress := normalizedStringBuffer,
characterCount => stringToCheckCodePointCount
);

__DELETE(normalizedStringBuffer);

IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS_NFD:
// string size can increase with NFD
normalizedStringBuffer := __NEW(BYTE, (stringToCheckByteCount * NORMALIZATION_FACTOR + 1));
IF normalizedStringBuffer = 0 THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('lengthIsExact, malloc failed'));
RETURN;
END_IF
bufferSize := stringToCheckByteCount * NORMALIZATION_FACTOR + 1; // stringsize can increase for NFD + NULL terminator

CNM_UnicodeUtilities.NormalizeUtf8String(
utf8StringBuffer := stringToCheck,
normalForm := CNM_UnicodeUtilities.NormalizationForm.NFD,
normalizedStringBuffer := normalizedStringBuffer,
bufferSize := bufferSize,
normalizedStringLength => normalizedLength
);

CNM_UnicodeUtilities.GetUtf8StringLength(
stringAddress := normalizedStringBuffer,
characterCount => stringToCheckCodePointCount
);

__DELETE(normalizedStringBuffer);

IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF

UnicodeStringLengthUnit.VISIBLE_CHARACTERS:
CNM_UnicodeUtilities.GetUtf8StringWidth(stringToCheck, visibleCharacters => visibleCharacters);
IF (visibleCharacters <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('lengthIsExact'));
END_IF

UnicodeStringLengthUnit.WIDTH:
width := CNM_UnicodeUtilities.GetUtf8StringWidth(stringToCheck);
IF ((width < 0) OR_ELSE (TO_UDINT(width) <> expectedLength)) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('LengthIsExact'));
END_IF
ELSE
; // do nothing
END_CASE