/* ========================================================================
* Copyright (c) 2005-2026 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
#if NET10_0
using System.Diagnostics;
using System.Text;
namespace Opc.Ua.Tools.Tests
{
///
/// Helpers for tests that assert on the console output of the
/// repository's PowerShell scripts.
///
internal static class PowerShellScriptOutput
{
///
/// Configures a pwsh process so its diagnostics are stable across
/// operating systems: no ANSI colouring, and no terminal-dependent
/// decoration.
///
public static void ConfigureDeterministicOutput(ProcessStartInfo startInfo)
{
startInfo.Environment["NO_COLOR"] = "1";
startInfo.Environment["TERM"] = "dumb";
}
///
/// Undoes the host formatting PowerShell applies to a terminating
/// error so a script's message can be matched verbatim.
///
///
/// PowerShell's default ConciseView renders a thrown message as a
/// block that is hard-wrapped to the console width, continuing each
/// line with a " | " marker. The console width differs per
/// operating system - the Windows agents are wide enough to emit the
/// message unwrapped, while the Linux and macOS agents fall back to
/// 80 columns - so an assertion on any phrase long enough to straddle
/// a wrap point passes on one agent and fails on another. Wrapping
/// always happens at a space, so rejoining the continuations with a
/// single space reconstructs the original message exactly.
///
public static string Normalize(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
var normalized = new StringBuilder(value.Length);
for (int ii = 0; ii < value.Length; ii++)
{
char character = value[ii];
if (character == '\u001b' && ii + 1 < value.Length && value[ii + 1] == '[')
{
ii += 2;
while (ii < value.Length && (value[ii] < '@' || value[ii] > '~'))
{
ii++;
}
continue;
}
if (character is '\r' or '\n' &&
TryMeasureContinuation(value, ii, out int length))
{
normalized.Append(' ');
ii += length - 1;
continue;
}
normalized.Append(character);
}
return normalized.ToString();
}
///
/// Measures a line break followed by a ConciseView continuation
/// marker: a run of horizontal whitespace, a '|', and the single
/// space that separates the marker from the wrapped text.
///
private static bool TryMeasureContinuation(string value, int start, out int length)
{
length = 0;
int index = start;
if (value[index] == '\r')
{
index++;
}
if (index >= value.Length || value[index] != '\n')
{
return false;
}
index++;
int whitespaceStart = index;
while (index < value.Length && (value[index] == ' ' || value[index] == '\t'))
{
index++;
}
if (index == whitespaceStart || index >= value.Length || value[index] != '|')
{
return false;
}
index++;
if (index < value.Length && (value[index] == ' ' || value[index] == '\t'))
{
index++;
}
length = index - start;
return true;
}
}
}
#endif