Skip to content

Commit

Permalink
Fixed #5: Convert byte arrays and strings
Browse files Browse the repository at this point in the history
  • Loading branch information
ygoe committed Aug 21, 2019
1 parent 240343f commit 15f6392
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
71 changes: 71 additions & 0 deletions DeepConvert.Tests/DeepConvertTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Unclassified.Util
Expand Down Expand Up @@ -283,5 +284,75 @@ public void ToDateTime_NoSeparators()
Assert.AreEqual(new DateTime(2010, 1, 1, 0, 0, 3), date);
Assert.AreEqual(DateTimeKind.Unspecified, date.Kind);
}

[TestMethod]
public void ChangeType_CharsToString()
{
char[] chars = new char[] { 'A', 'ö', 'b', 'c', '€' };
string str = DeepConvert.ChangeType<string>(chars);
Assert.AreEqual("Aöbc€", str);

int[] numbers = new int[] { 0x41, 0xf6, 0x62, 0x63, 0x20ac };
str = DeepConvert.ChangeType<string>(numbers);
Assert.AreEqual("Aöbc€", str);

object[] mixed = new object[] { "A", 'ö', 0x62, "c", "€" }; // numeric strings not supported, must be single characters
str = DeepConvert.ChangeType<string>(mixed);
Assert.AreEqual("Aöbc€", str);
}

[TestMethod]
public void ChangeType_StringToChars()
{
string str = "Aöbc€";
var chars = DeepConvert.ChangeType<List<char>>(str);
Assert.AreEqual(5, chars.Count);
Assert.AreEqual('A', chars[0]);
Assert.AreEqual('ö', chars[1]);
Assert.AreEqual('b', chars[2]);
Assert.AreEqual('c', chars[3]);
Assert.AreEqual('€', chars[4]);
}

[TestMethod]
public void ChangeType_BytesToString()
{
byte[] bytes = new byte[] { /*A*/ 0x41, /*ö*/ 0xc3, 0xb6, /*b*/ 0x62, /*c*/ 0x63, /*€*/ 0xe2, 0x82, 0xac };
string str = DeepConvert.ChangeType<string>(bytes); // default UTF-8
Assert.AreEqual("Aöbc€", str);

bytes = new byte[] { /*A*/ 0x41, 0, /*ö*/ 0xf6, 0, /*b*/ 0x62, 0, /*c*/ 0x63, 0, /*€*/ 0xac, 0x20 };
str = DeepConvert.ChangeType<string>(bytes, new DeepConvertSettings { Encoding = Encoding.Unicode });
Assert.AreEqual("Aöbc€", str);
}

[TestMethod]
public void ChangeType_StringToBytes()
{
string str = "Aöbc€";
var bytes = DeepConvert.ChangeType<List<byte>>(str); // default UTF-8
Assert.AreEqual(8, bytes.Count);
Assert.AreEqual(0x41, bytes[0]); // A
Assert.AreEqual(0xc3, bytes[1]); // ö
Assert.AreEqual(0xb6, bytes[2]);
Assert.AreEqual(0x62, bytes[3]); // b
Assert.AreEqual(0x63, bytes[4]); // c
Assert.AreEqual(0xe2, bytes[5]); // €
Assert.AreEqual(0x82, bytes[6]);
Assert.AreEqual(0xac, bytes[7]);

byte[] bytesArr = DeepConvert.ChangeType<byte[]>(str, new DeepConvertSettings { Encoding = Encoding.Unicode });
Assert.AreEqual(10, bytesArr.Length);
Assert.AreEqual(0x41, bytesArr[0]); // A
Assert.AreEqual(0, bytesArr[1]);
Assert.AreEqual(0xf6, bytesArr[2]); // ö
Assert.AreEqual(0, bytesArr[3]);
Assert.AreEqual(0x62, bytesArr[4]); // b
Assert.AreEqual(0, bytesArr[5]);
Assert.AreEqual(0x63, bytesArr[6]); // c
Assert.AreEqual(0, bytesArr[7]);
Assert.AreEqual(0xac, bytesArr[8]); // €
Assert.AreEqual(0x20, bytesArr[9]);
}
}
}
31 changes: 28 additions & 3 deletions DeepConvert/DeepConvert.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018, Yves Goergen, http://unclassified.software
// Copyright (c) 2018-2019, Yves Goergen, https://unclassified.software
//
// 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,
Expand Down Expand Up @@ -185,7 +185,6 @@ public static object ChangeType(object value, Type destType, DeepConvertSettings
if (destType == typeof(DateTime)) return ToDateTime(value, settings); //DateTime.Parse((string)value, provider);
if (destType == typeof(TimeSpan)) return TimeSpan.Parse((string)value, provider);
if (destType == typeof(Guid)) return Guid.Parse((string)value);
// TODO: Convert with collection of chars (also in reverse direction)
}
if (srcType == typeof(char))
{
Expand Down Expand Up @@ -438,10 +437,27 @@ public static object ChangeType(object value, Type destType, DeepConvertSettings
// any classes implementing: ICollection<> (includes IList<>, ISet<>), IList
// dictionaries are considered collections of KeyValuePair:
// Dictionary<,>, ConcurrentDictionary<,>, IDictionary<,>, IDictionary
// strings are also considered collections of chars, if converting from/to collections

// Convert from bytes to string
if (typeof(IEnumerable<byte>).IsAssignableFrom(srcType) &&
destType == typeof(string))
{
var encoding = settings.Encoding ?? Encoding.UTF8;
var bytes = (IEnumerable<byte>)value;
return encoding.GetString(bytes.ToArray());
}

// Convert between collection types, then recurse into each item
IEnumerable<object> items = null;
if (typeof(IEnumerable).IsAssignableFrom(srcType))
// Convert from string to bytes
if (srcType == typeof(string) &&
typeof(IEnumerable<byte>).IsAssignableFrom(destType))
{
var encoding = settings.Encoding ?? Encoding.UTF8;
items = encoding.GetBytes((string)value).Cast<object>();
}
else if (typeof(IEnumerable).IsAssignableFrom(srcType))
{
items = ((IEnumerable)value).Cast<object>();
}
Expand Down Expand Up @@ -525,6 +541,15 @@ public static object ChangeType(object value, Type destType, DeepConvertSettings
}
return list;
}
if (destType == typeof(string))
{
var sb = new StringBuilder(items.Count());
foreach (char item in items.Select(o => ChangeType(o, typeof(char), settings)))
{
sb.Append(item);
}
return sb.ToString();
}
}

// TODO: Convert between atomic and collection types (needs recursion?) (take care of KeyValuePair (a tuple) <-> Dictionary (a collection))
Expand Down

0 comments on commit 15f6392

Please sign in to comment.