Skip to content

Commit

Permalink
Wip Parse StringType
Browse files Browse the repository at this point in the history
  • Loading branch information
patrick-dmxc committed Oct 2, 2024
1 parent 5094b6a commit 1aabd78
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 22 deletions.
105 changes: 84 additions & 21 deletions RDMSharp/Metadata/JSON/OneOfTypes/StringType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,28 @@ public StringType(string name,
MaxBytes = maxBytes;
RestrictToASCII = restrictToASCII;
}

public StringType(
string name,
string displayName,
string notes,
string format,
string pattern,
uint length,
bool? restrictToASCII = null) : this(
name,
displayName,
notes,
null,
"string",
format,
pattern,
minLength: length,
maxLength: length,
null,
null,
restrictToASCII)
{
}
public override string ToString()
{
return base.ToString();
Expand Down Expand Up @@ -120,13 +141,25 @@ public override byte[] ParsePayloadToData(DataTree dataTree)

if (dataTree.Value is string @string)
{
if (MaxLength.HasValue)
@string = @string.Substring(0, (int)MaxLength);
if (MinLength.HasValue && MinLength.Value > @string.Length)
throw new ArithmeticException($"The given String is smaller then {nameof(MinLength)}: {MinLength}");
if (MaxLength.HasValue && MaxLength.Value < @string.Length)
throw new ArithmeticException($"The given String is larger then {nameof(MaxLength)}: {MaxLength}");

Encoding encoder = null;
if (RestrictToASCII == true)
Encoding.ASCII.GetBytes(@string);
encoder = Encoding.ASCII;
else
Encoding.UTF8.GetBytes(@string);
encoder = Encoding.UTF8;

var data = encoder.GetBytes(@string);

if (MinBytes.HasValue && MinBytes.Value > data.Length)
throw new ArithmeticException($"The given String encoded is smaller then {nameof(MinBytes)}: {MinBytes}");
if (MaxBytes.HasValue && MaxBytes.Value < data.Length)
throw new ArithmeticException($"The given String encoded is larger then {nameof(MaxBytes)}: {MaxBytes}");

return data;
}

throw new ArithmeticException($"The given Object from {nameof(dataTree.Value)} can't be parsed");
Expand All @@ -135,32 +168,62 @@ public override byte[] ParsePayloadToData(DataTree dataTree)
public override DataTree ParseDataToPayload(ref byte[] data)
{
List<DataTreeIssue> issueList = new List<DataTreeIssue>();
if (MaxBytes.HasValue && data.Length > MaxBytes)
if (MaxBytes.HasValue && data.Length > MaxBytes.Value)
issueList.Add(new DataTreeIssue($"Data length exceeds {nameof(MaxBytes)}, the Data has {data.Length}, but {nameof(MaxBytes)} is {MaxBytes}"));
if (MinBytes.HasValue && data.Length < MinBytes)
if (MinBytes.HasValue && data.Length < MinBytes.Value)
issueList.Add(new DataTreeIssue($"Data length falls shorts of {nameof(MinBytes)}, the Data has {data.Length}, but {nameof(MinBytes)} is {MinBytes}"));

string str = null;
uint length = (uint)data.Length;
if (MaxLength.HasValue)
length = MaxLength.Value;
if (MaxBytes.HasValue)
length = MaxBytes.Value;

if (data.Any(c => c == 0))
length = (uint)data.TakeWhile(c => c != 0).Count() + 1;

byte[] dataBytes = data;
int charLength = 0;
int byteLength = 0;
int takenBytesCount = 0;
if (RestrictToASCII == true)
str = Encoding.ASCII.GetString(data, 0, (int)length);
parse(Encoding.ASCII);
else
str = Encoding.UTF8.GetString(data, 0, (int)length);
parse(Encoding.UTF8);

void parse(Encoding encoder)
{
str = encoder.GetString(dataBytes);
takenBytesCount = dataBytes.Length;

string[] strings = str.Split((char)0);
if (strings.Where(s => string.IsNullOrEmpty(s)).Count() > 1)
issueList.Add(new DataTreeIssue("More then one Null-Delimiter"));
if (strings.Skip(1).Any(s => !string.IsNullOrEmpty(s)))
issueList.Add(new DataTreeIssue("Trailing Characters"));

str = strings.First();
byteLength = encoder.GetBytes(str).Length;
takenBytesCount = byteLength;
charLength = str.Length;
bool repeatParse = false;
if (MaxLength.HasValue && MaxLength < charLength)
{
charLength = (int)MaxLength.Value;
repeatParse = true;
}
if (MaxBytes.HasValue && MaxBytes < byteLength)
{
byteLength = (int)MaxBytes.Value;
repeatParse = true;
}
if (repeatParse)
{
dataBytes = dataBytes.Take(byteLength).ToArray();
str = encoder.GetString(dataBytes);
takenBytesCount = dataBytes.Length;
}

}

if (MaxLength.HasValue && str.Length > MaxLength)
if (MaxLength.HasValue && str.Length > MaxLength.Value)
issueList.Add(new DataTreeIssue($"String length exceeds {nameof(MaxLength)}, the Data has {str.Length}, but {nameof(MaxLength)} is {MaxLength}"));
if (MinLength.HasValue && str.Length < MinLength)
if (MinLength.HasValue && str.Length < MinLength.Value)
issueList.Add(new DataTreeIssue($"String length falls shorts of {nameof(MinLength)}, the Data has {str.Length}, but {nameof(MinLength)} is {MinLength}"));

data = data.Skip((int)length).ToArray();
data = data.Skip(takenBytesCount).ToArray();
return new DataTree(this.Name, 0, str, issueList.Count != 0 ? issueList.ToArray() : null);
}
}
Expand Down
136 changes: 135 additions & 1 deletion RDMSharpTests/Metadata/JSON/TestStringType.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using RDMSharp.Metadata;
using RDMSharp.Metadata.JSON.OneOfTypes;
using RDMSharp.RDM;

Expand All @@ -8,7 +9,7 @@ public class TestStringType
[Test]
public void TestMany()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null,null,null,null,null,null,null);
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, null, null, null);
Assert.That(stringType.MinLength, Is.Null);
Assert.That(stringType.MaxLength, Is.Null);

Expand Down Expand Up @@ -41,5 +42,138 @@ public void TestMany()

Assert.Throws(typeof(ArgumentException), () => stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "sting", null, null, null, null, null, null, null));
}
[Test]
public void TestParseFixedLengthASCII()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, null, 5, true);
string str = "qwert";
DataTree dataTree = new DataTree("NAME", 0, str);
byte[] data = stringType.ParsePayloadToData(dataTree);
Assert.That(data, Is.EqualTo(new byte[] { 113, 119, 101, 114, 116 }));
DataTree reverseDataTree = stringType.ParseDataToPayload(ref data);
Assert.Multiple(() =>
{
Assert.That(data, Has.Length.Zero);
Assert.That(reverseDataTree, Is.EqualTo(dataTree));
});
}
[Test]
public void TestParseFixedLengthInBytesUTF8()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, minBytes: 8, maxBytes: 8, null);
string str = "ÄÜÖß";
DataTree dataTree = new DataTree("NAME", 0, str);
byte[] data = stringType.ParsePayloadToData(dataTree);
Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 195, 156, 195, 150, 195, 159 }));
DataTree reverseDataTree = stringType.ParseDataToPayload(ref data);
Assert.Multiple(() =>
{
Assert.That(data, Has.Length.Zero);
Assert.That(reverseDataTree, Is.EqualTo(dataTree));
});
}
[Test]
public void TestParseRangedLengthUTF8()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 4, 6, null, null, null);
string str = "ÄÜÖß";
DataTree dataTree = new DataTree("NAME", 0, str);
byte[] data = stringType.ParsePayloadToData(dataTree);
Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 195, 156, 195, 150, 195, 159 }));
DataTree reverseDataTree = stringType.ParseDataToPayload(ref data);
Assert.Multiple(() =>
{
Assert.That(data, Has.Length.Zero);
Assert.That(reverseDataTree, Is.EqualTo(dataTree));
});
}
[Test]
public void TestParseRangedLengthUTF8Mixed()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 4, 6, 4, 8, null);
string str = "ÄUÖS";
DataTree dataTree = new DataTree("NAME", 0, str);
byte[] data = stringType.ParsePayloadToData(dataTree);
Assert.That(data, Is.EqualTo(new byte[] { 195, 132, 85, 195, 150, 83 }));
DataTree reverseDataTree = stringType.ParseDataToPayload(ref data);
Assert.Multiple(() =>
{
Assert.That(data, Has.Length.Zero);
Assert.That(reverseDataTree, Is.EqualTo(dataTree));
});
}

[Test]
public void TestParseExceptions()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 3, 6, 5, 8, null);
string str = "12";
DataTree dataTree = new DataTree("NAME FAIL", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
str = "1234";
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
str = "1234567";
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));

stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 5, 8, null);

str = "ÄÖÜ4567";
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
str = "ÄÖÜÜÖÄ";
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
str = null;
dataTree = new DataTree("NAME", 0, str);
Assert.Throws(typeof(ArithmeticException), () => stringType.ParsePayloadToData(dataTree));
}

[Test]
public void TestParseBadFormatedData1()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, null, null, 2, 8, null);
byte[] data = new byte[] { 195, 132, 0, 0, 0, 0 };
var dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo("Ä"));
Assert.That(dataTree.Issues, Has.Length.EqualTo(1));

data = new byte[] { 195, 132, 0, 0, 119, 0 };
dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo("Ä"));
Assert.That(dataTree.Issues, Has.Length.EqualTo(2));

data = new byte[] { 0, 0, 0, 0, 0, 0 };
dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo(string.Empty));
Assert.That(dataTree.Issues, Has.Length.EqualTo(1));

data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo(string.Empty));
Assert.That(dataTree.Issues, Has.Length.EqualTo(2));

data = new byte[] { };
dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo(string.Empty));
Assert.That(dataTree.Issues, Has.Length.EqualTo(1));
}
[Test]
public void TestParseBadFormatedData2()
{
var stringType = new StringType("NAME", "DISPLAY_NAME", "NOTES", null, "string", null, null, 2, 4, null, null, null);
byte[] data = new byte[] { 195, 132, 0, 0, 0, 0 };
var dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo("Ä"));
Assert.That(dataTree.Issues, Has.Length.EqualTo(2));

data = new byte[] { 195, 132, 119, 119, 119, 119, 0 };
dataTree = stringType.ParseDataToPayload(ref data);
Assert.That(dataTree.Value, Is.EqualTo("Äwwww"));
Assert.That(dataTree.Issues, Has.Length.EqualTo(1));
}
}
}

0 comments on commit 1aabd78

Please sign in to comment.