Get resource hex/ascii \n\r value not converted one - c#

Greeting,
We have some translation stored in a resx file which contains a break line similar to:
"This is a Test
& or something similar. "
There are ~50 devs in our project and from time to time Visual studio corrects the translation into
"This is a Test
& or something similar. " causing our pipeline to fail (long story)
Now my goal is to write a test and to ensure that the translations are not "corrupted", but I found no way to get the actual hex or ASCII value of the string above.
It always comes as \n\r .
I also want to mention that I would like not to change the current behavior of the app, only to get the proper ASCII or hex from the resource
This is what I would like to get from the resx file using: GetString or similar
&# xA;&# xD;
&# 13;&# 10;
[TestMethod]
public void Test()
{
// Arrange
var x = ToLiteral("This is a Test
&& or something similar.");
// Act
var xExpected = ToLiteral(Resources.Something.Some_Title);
// Assert
x.ShouldBe(xExpected );
}
private static string ToLiteral(string valueTextForCompiler)
{
return Microsoft.CodeAnalysis.CSharp.SymbolDisplay.FormatLiteral(valueTextForCompiler, false);
}

Related

Logging reserved words/characters

I have a *.resx string that looks like this:
Failed to deserialize an object of type '{0}' from the following string:{1}{2}
This string is being used to log such kinds of errors and currently, the logging statement looks like this:
_logger.LogError(Resources.FailedToDeserialize, typeof(MyType).Name, Environment.NewLine, invalidJsonString);
As you can see - I need to pass Environment.NewLine each time to display my logs correctly for any OS.
I am curious are there any reserved string interpolation words/characters to insert such values?
For example, my string could look like this:
Failed to deserialize an object of type '{0}' from the following string:{NewLine}{2}
And my logging statement would be a bit simpler:
_logger.LogError(Resources.FailedToDeserialize, typeof(MyType).Name, invalidJsonString);
One thing you can do is some form of pre processing on application start up by reading the resource file, replacing your keyword of choice i.e {NewLine} with Environment.NewLine and then use that cached string for the entirety of your application life time.
You can make the fields readonly and do some reflection magic to set the value but this example should give you an idea of how to solve your current problem.
public static class LoggingMessageTemplates
{
//Reference your resource here e.g Resource.FailedToDeserialize
public static string FailedToDeserialize = "Resource.Something {NewLine} Something Else";
public static void FormatMessages()
{
var stringFields = typeof(LoggingMessageTemplates)
.GetFields()
.Where(x => x.FieldType == typeof(string));
foreach(var field in stringFields)
{
if (field.GetValue(null) is not string fieldValue)
{
throw new InvalidCastException($"Failed to cast field {field.Name} to string.");
}
field.SetValue(null, fieldValue.Replace("{NewLine}", Environment.NewLine));
}
}
}
//On application startup, format the resources to use the Environment.NewLine char of the current system.
LoggingMessageTemplates.FormatMessages();
//When logging, reference the LoggingMessageTemplates class rather than the direct resource.
Console.WriteLine(LoggingMessageTemplates.FailedToDeserialize);
//i.e
_logger.LogError(LoggingMessageTemplates.FailedToDeserialize, typeof(MyType).Name, invalidJsonString);

Get source file location with DeterministicSourcePaths turned on

Question:
Is there a way how to get the Caller or current frame source code location without using the CallerFilePath attribute?
Background:
I have this helper defined:
public class PathHelper
{
public static string GetThisFilePath([CallerFilePath] string path = null)
{
return path;
}
}
That can be called as follows to obtain the location of source code used to build the binary:
var currentSourceFilePath = PathHelper.GetThisFilePath();
This works fine, unless I have DeterministicSourcePaths turned on (typically via ContinuousIntegrationBuild msbuild property). In such a case the returned paths are trimmed to something like:
/_/MyRelativeSourcePath
So it seems that determinist paths are injected into the compiler functionality supporting CallerFilePath yielding this behavior.
I need the source code location in order to be able to unit test product specific functionality (that has to do with inspecting build process), while I'd still like to support fully determinisitc build on CI machines.
You may try something like following. Please note
this is just an idea, exact implementation depends on your environment
This would be working if you are using "default build output paths" only
I didn't tested it
public static string GetThisFilePath([CallerFilePath] string path = null)
{
const string determenisticRoot = "/_/";
if(!path.StartsWith(determenisticRoot))
{
return path;
}
// callerBinPath would be something like $(SolutionRoot)/.../MyProject.Tests/bin/Debug/net5.0
var callerBinPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
// Traverse to $(TestProjectRoot) - testProjectRoot would be something like $(SolutionRoot)/.../MyProject.Tests
var testProjectRoot = Path.Combine(callerExecutablePath, "../../..");
// Combine projectRoot root with relative path from [CallerFilePath]
return Path.Combine(testProjectRoot, path.Substring(determenisticRoot.Length));
}

Testing validations C#

Below I've pasted my code. I'm validating a measure. I've written code that will read a Linux file. But if I wanted to pass multiple file names here would this be possible? so for example instead of my test just validating one file could I do a loop so it could ready multiple files in one go.
Once the file is being read and proceeded I return actualItemData. In my next method, I want to make a call to this actualItemData so the data is published in my var actual
public string validateMeasurement
{
var processFilePath = **"/orabin/app/oracle/inputs/ff/ff/actuals/xx_ss_x.csv.ovr";**
var actualItemData = Common.LinuxCommandExecutor.
RunLinuxcommand("cat " + processFilePath);
**return actualItemData;**
}
public void validateInventoryMeasurementValue(string Data, string itemStatus)
{
var expected = '6677,6677_6677,3001,6';
**var actual = actualItemData);**
Assert.AreEqual(expected, actual);
}
It looks like you are using msunit. As far as I know it doesn't support test cases. If you were to use nunit you would be able to do this using the TestCase attribute.
[TestCase("myfile1.txt", "6677,6677_6677,3001,6")]
[TestCase("myfile2.txt", "1,2,3")]
public void mytest(string path, string expected)
{
var actual = Common.LinuxCommandExecutor.
RunLinuxcommand("cat " + path);
Assert.AreEqual(expected, actual);
}
Generally you don't want to write unit tests that cross code boundaries (read files, hit the database, etc) as these tests tend to be brittle and difficult to maintain. I am not sure of the aim of your code but it appears you may be trying to parse the data to check it's validity. If this is the case you could write a series of tests to ensure that when your production code (parser) is given a string input, you get an output that matches your expectation. e.g.
[Test()]
public void Parse_GivenValidDataFromXX_S_X_CSV_ShouldReturnTrue(string filename)
{
// Arrange
var parser = CreateParser(); // factory function that returns your parser
// Act
var result = parser.Parse("6677,6677_6677,3001,6");
// Arrage
Assert.IsTrue(result);
}

Checking the values of a dictionary against a string being read in externally

I've created a dictionary like so:
public Dictionary<string, string> myValues = new Dictionary<string, string>();
Then in my start method I'm filling out my dictionary like so:
void Start()
{
myValues.Add("device one", "11111111111111");
}
And what I'm trying to do is check the value that I've created in my dictionary, in the above example it would be the 1111111111111, against a string value that is being read in remotely. The check I'm doing is this:
void Update ()
{
// Spawn a model based on the signal the ipad has recievied.
if( myValues["device one"] == outputContent.text)
{
Instantiate(model1, new Vector3(-2.5f, 3.0f,0), Quaternion.identity);
}
}
The message is getting parsed from a wrapper class that takes information from native ipad stuff and passes it direct to unity. The method for getting the message is this:
private void AppendString(string message)
{
outputContent.text += "\n" + message;
}
Now, the thing is, the message getting passed works. When I run my code, the screen gets filled with the information I want. But when I try to check the values I've stored against the ones getting sent in, nothing happens.
How I got my initial hard coded value was by first reading them in from the AppendString method. And I've double checked them to make sure I've got the correct information down.
Can someone please tell me if I'm comparing the values held within my dictionary, to those being read in, is correct?
There's a couple of 'suspicious' spots.
Here, you add \n, are you sure that's included in the dictionary's value?
outputContent.text += "\n" + message;
Also, make sure you compare the strings properly. It may even be a capitalization problem, something that's bitten me many times. Try for instance:
if(String.Equals(myValues["device one"], outputContent.text, StringComparison.OrdinalIgnoreCase)
better replace following line
if( myValues["device one"] == outputContent.text)
with:
if( myValues["device one"].Equals(outputContent.text))

C# String Property and string literal concatenation issue

I am a bit new at C# and I have run into a string concatenation issue. I am hoping someone might be able to give me a hint and help me resolve this. I have searched Google extensively and have spent more than a week on this so any help/advice would be greatly appreciated.
I have created a custom PathEditor for a string property. The property basically allows the user to key in a file to use in the app. If the file typed in is correct, it shows in the property cell as it should. What I am trying to do is output to the property cell an error message if the file typed in does not exist - I check this in my file validator. Here is the string literal issue.
If I use:
return inputFile+"Error_";
this works OK and I get the outpur file123.txtError_ in the property grid cell.
If I use:
return "Error_"+inputFile;
I get only the inputFile without the literal "Error_". Sot he property grid cell shows file123.txt in the property grid cell.
I have checked and inputFile is a string type. Any ideas as to why this is happening?
Also, is there any way to change to font, and/or, color of the message output? I tried to change the background of the property grid cell and I understand that this is not possible to do.
Thank you.
Z
More of the code:
[
Description("Enter or select the wave file. If no extension, or a non .wav extension, is specified, the default extension .wav will be added to the filename."),
GridCategory("Sound"),
Gui.Design.DisplayName ("Input Sound"),
PathEditor.OfdParamsAttribute("Wave files (*.wav)|*.wav", "Select Audio File"),
Editor(typeof(PathEditor), typeof(System.Drawing.Design.UITypeEditor))
]
public string InputWavefile
{
get { return System.IO.Path.GetFileName(inputtWavefile); }
set
{
if (value != inputWavefile) // inputWavefile has been changed
{
// validate the input stringg
_inputWavefile = FileValidation.ValidateFile(value);
// assign validated value
inputWavefile = _inputWavefile;
}
}
}
My guess is that you've got a funky character at the start of inputFile which is confusing things - try looking at it in the debugger using inputFile.ToCharArray() to get an array of characters.
The string concatenation itself should be fine - it's how the value is being interpreted which is the problem, I suspect...
I'm guessing your filename looks something like this, C:\Folder\FileName.txt when you start out.
In your FileValidation.ValidateFile() method you
return "Error_" + InputFileName;
it now looks like this: Error_C:\Folder\FileName.txt.
So, when you run the line below,
get { return System.IO.Path.GetFileName( _inputWavefile ); }
it strips off the path and returns the filename only, FileName.txt.
Even when the filename is not valid, you are still running System.IO.Path.GetFileName() on it.
Assuming this is a PropertyGrid in winforms app. Then it's neither a string concatenation issue, nor PropertyGrid issue, as could be proven by the following snippet. So you need to look elsewhere in your code:
public partial class Form1 : Form {
PropertyGrid pg;
public Form1() {
pg = new PropertyGrid();
pg.Dock = DockStyle.Fill;
this.Controls.Add(pg);
var inputFile = "some fileName.txt";
var obj = new Obj();
obj.One = "Error_" + inputFile;
obj.Two = inputFile + "Error_";
pg.SelectedObject = obj;
}
}
class Obj {
public string One { get; set; }
public string Two { get; set; }
}

Categories

Resources