Commit 173b26ee authored by Jeremy Banks's avatar Jeremy Banks

Add a test structure that should be able to fully exercise type mapping, and...

Add a test structure that should be able to fully exercise type mapping, and logging in the type mapping file.
parent 8303b49b
Pipeline #6972064 passed with stage
in 1 minute and 25 seconds
......@@ -81,12 +81,9 @@ namespace Ditto {
sub.Description = "Temporary test command";
sub.HelpOption("-h | --help | -?");
var verboseOption = sub.Option(
"-v | --verbose", "Enables verbose logging", CommandOptionType.NoValue);
sub.OnExecute(() => {
GlobalLogger.LoggerFactory.AddConsole(
verboseOption.HasValue() ? LogLevel.Debug : LogLevel.Information, true);
GlobalLogger.LoggerFactory.AddConsole(LogLevel.Debug);
var value = Bencoding.Decode<ScratchTarget>("d4:name5:worlde".ToASCII());
......
......@@ -5,7 +5,7 @@ using System.IO;
using Ditto.Common;
namespace Ditto.Serialization {
public static partial class Bencoding {
public partial class Bencoding {
public static T Decode<T>(byte[] bytes) where T : new() {
return bToType<T>(decode(bytes));
}
......
......@@ -6,7 +6,7 @@ using System.Linq;
using Ditto.Common;
namespace Ditto.Serialization {
public static partial class Bencoding {
public partial class Bencoding {
public static byte[] Encode(object value) {
using (var stream = new MemoryStream()) {
Encode(stream, value);
......
......@@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Ditto.Common;
using Microsoft.Extensions.Logging;
namespace Ditto.Serialization {
// Utilities for mapping between bencoding structures and other data types.
public static partial class Bencoding {
public partial class Bencoding {
public static T bToType<T>(object bData) where T : new() {
var targetType = typeof(T);
......@@ -15,7 +16,8 @@ namespace Ditto.Serialization {
var fields = targetType.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine($"I see {fields.Length} fields and {props.Length} props for {targetType}.");
logger.BeginScope($"mapping to {targetType}");
logger.LogDebug($"found {fields.Length} fields and {props.Length}");
// NOTE: This logic is not yet considering list or dict types, just classes.
var bDict = (Dictionary<byte[], object>) bData;
......@@ -25,27 +27,31 @@ namespace Ditto.Serialization {
var result = new T();
foreach (var field in fields) {
Console.WriteLine("see field:" + field.Name);
var bAttrs = field.GetCustomAttributes(typeof(BencodableAttribute)).ToList();
if (bAttrs.Count == 1) {
var attr = (BencodableAttribute) bAttrs[0];
var key = attr.Key;
Console.WriteLine("MAPPABLE!!! " + key);
logger.LogDebug($"found mappable prop: {key.ToHuman()} to {field.Name}:{field.FieldType}");
if (keysSeen.Contains(key)) {
throw new BencodingTypeMappingException(
$"[Bencodable(\"{key}\")] specified for multiple properties.");
$"[Bencodable(\"{key}\")] specified for multiple props/fields.");
} else {
keysSeen.Add(key);
if (!bDict.ContainsKey(key)) {
continue;
}
var type = field.FieldType;
var bValue = bDict[key];
object value;
if (type == typeof(byte[])) {
value = (byte[]) bValue;
} else if (type == typeof(string)) {
value = ((string) bValue).ToASCII();
value = ((byte[]) bValue).FromASCII();
} else {
throw new BencodingTypeMappingException($"Can't map field of type {type}.");
logger.LogError($"Can't map field of type {type}.");;
continue;
}
field.SetValue(result, value);
}
......@@ -56,15 +62,14 @@ namespace Ditto.Serialization {
}
foreach (var prop in props) {
Console.WriteLine("see prop:" + prop.Name);
var bAttrs = prop.GetCustomAttributes(typeof(BencodableAttribute)).ToList();
if (bAttrs.Count == 1) {
var attr = (BencodableAttribute) bAttrs[0];
var key = attr.Key;
Console.WriteLine("MAPPABLE!!! " + key);
logger.LogDebug($"found mappable prop: {key.ToHuman()} to {prop.Name}:{prop.PropertyType}");
if (keysSeen.Contains(key)) {
throw new BencodingTypeMappingException(
$"[Bencodable(\"{key}\")] specified for multiple properties.");
$"[Bencodable(\"{key}\")] specified for multiple props/fields.");
} else {
keysSeen.Add(key);
......
......@@ -3,10 +3,13 @@ using System.Collections.Generic;
using System.Text;
using Ditto.Common;
using Microsoft.Extensions.Logging;
namespace Ditto.Serialization {
// Utility functions for bencoded data.
public static partial class Bencoding {
public partial class Bencoding {
static ILogger logger { get; } = GlobalLogger.CreateLogger<Bencoding>();
// Returns a new Dictionary that can be directly bencoded.
public static Dictionary<byte[], object> Dict() {
return new Dictionary<byte[], object>(ByteArrayComparer.Instance);
......
......@@ -4,11 +4,16 @@ using Xunit;
using Ditto.Common;
using Ditto.Serialization;
using Microsoft.Extensions.Logging;
namespace Ditto.UnitTests
{
public class SerializationTests
{
static SerializationTests() {
GlobalLogger.LoggerFactory.AddConsole(LogLevel.Debug);
}
// Asserts that deserializing and reserializing doesn't modify a value.
public void AssertRoundTrip(byte[] bytes) {
var value = Bencoding.DecodeDynamic(bytes);
......@@ -399,5 +404,69 @@ namespace Ditto.UnitTests
Assert.Equal(typeof(Dictionary<byte[], object>), result.GetType());
AssertRoundTrip(value);
}
[Fact]
public void TypedTorrentLikeFromBytes()
{
var value = (
"d8:announce35:udp://tracker.openbittorrent.com:8013:announce-list" +
"ll35:udp://tracker.openbittorrent.com:80el33:udp://tracker.opentrackr.org:1337ee" +
"4:infod6:lengthi7e4:name7:example12:piece lengthi7e6:pieces20:0I0')s000000v0-0o0?0" +
"4:salt3:200e8:url-listl57:https://mgnt.ca/123456fc77d23aca05a8b58066bb55fe06c72f8e/" +
"56:http://mgnt.ca/123456fc77d23aca05a8b58066bb55fe06c72f8e/ee").ToASCII();
var result = Bencoding.Decode<PseudoTorrent>(value);
Assert.Equal("udp://tracker.openbittorrent.com:80", result.Tracker);
}
class PseudoTorrent {
[Bencodable("announce")]
public string Tracker;
[Bencodable("announce-list")]
public IList<IList<string>> TrackersByTier;
[Bencodable("url-list")]
public IList<string> WebSeedURLs;
[Bencodable("info")]
public InfoData Info;
public class InfoData {
[Bencodable("piece length")]
public Int64 PieceLength;
[Bencodable("length")]
public Int64 Length;
[Bencodable("name")]
public string Name;
[Bencodable("pieces")]
public byte[] PieceHashes;
[Bencodable("files")]
public IList<FileData> RawFilesDict;
public class FileData {
[Bencodable("path")]
public IList<string> Path;
[Bencodable("length")]
public Int64 Length;
}
}
[Bencodable("signatures")]
public IDictionary<byte[], SignatureData> Signatures;
public class SignatureData {
[Bencodable("certificate")]
byte[] Certificate;
[Bencodable("signature")]
byte[] Signature;
[BencodableAttribute("info")]
public IDictionary<byte[], object> ExtensionsInfo;
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment