从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace YLErp
|
||||
{
|
||||
[TestClass]
|
||||
public class UnitTestBase
|
||||
{
|
||||
protected OptUserInfo GetOptUser([CallerMemberName] string m_name = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_name) || m_name == ".ctor")
|
||||
{
|
||||
m_name = GetType().Name;
|
||||
}
|
||||
|
||||
return new OptUserInfo(0, m_name, OptUserFrom.UnitTest, userGroup: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取资源文件所有文本
|
||||
/// </summary>
|
||||
protected static string ReadResourceFile(string relativeFilePath)
|
||||
{
|
||||
var path = Path.Combine(AppContext.BaseDirectory, "Resources\\" + relativeFilePath);
|
||||
return File.ReadAllText(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取资源文件所有行
|
||||
/// </summary>
|
||||
protected static string[] ReadResourceFileLines(string relativeFilePath)
|
||||
{
|
||||
var path = Path.Combine(AppContext.BaseDirectory, "Resources\\" + relativeFilePath);
|
||||
return File.ReadAllLines(path);
|
||||
}
|
||||
|
||||
protected static T DeserializeFormData<T>(string resourceFileRelativePath) where T : new()
|
||||
{
|
||||
var list = new List<KeyValuePair<string, string>>();
|
||||
var lines = ReadResourceFileLines(resourceFileRelativePath);
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var index = line.IndexOf(':');
|
||||
if (index < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list.Add(new KeyValuePair<string, string>(line.Substring(0, index).Trim(), line.Substring(index + 1).Trim()));
|
||||
}
|
||||
|
||||
var fc = new FormDataCollection(list);
|
||||
|
||||
return MapForm<T>(fc.ReadAsNameValueCollection(), "");
|
||||
}
|
||||
|
||||
protected class OtcOptionTradeFullFormData
|
||||
{
|
||||
public IEnumerable<OtcOptionTradeFull> trades { get; set; }
|
||||
}
|
||||
|
||||
private static readonly Regex _regex = new(@"\[(?<value>.*?)\]", RegexOptions.Compiled | RegexOptions.Singleline);
|
||||
|
||||
private static T MapForm<T>(NameValueCollection nvc, string rootObjectName) where T : new()
|
||||
{
|
||||
var result = new T();
|
||||
|
||||
foreach (var kvp in nvc.AllKeys)
|
||||
{
|
||||
if (!kvp.StartsWith(rootObjectName))
|
||||
{
|
||||
throw new Exception("All keys should start with " + rootObjectName);
|
||||
}
|
||||
|
||||
var match = _regex.Match(kvp.Remove(0, rootObjectName.Length));
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
// build path in a form of [Documents, 0, DocumentID]-like array
|
||||
var path = new List<string>();
|
||||
while (match.Success)
|
||||
{
|
||||
path.Add(match.Groups["value"].Value);
|
||||
match = match.NextMatch();
|
||||
}
|
||||
// this is object we currently working on
|
||||
object currentObject = result;
|
||||
for (var i = 0; i < path.Count; i++)
|
||||
{
|
||||
var last = i == path.Count - 1;
|
||||
var propName = path[i];
|
||||
if (int.TryParse(propName, out var index))
|
||||
{
|
||||
// index access, like [0]
|
||||
var list = currentObject as IList;
|
||||
if (list == null)
|
||||
{
|
||||
throw new Exception("Invalid index access expression"); // more info here
|
||||
}
|
||||
// get the type of item in that list (i.e. Document)
|
||||
var args = list.GetType().GetGenericArguments();
|
||||
var listItemType = args[0];
|
||||
if (last)
|
||||
{
|
||||
// may need more sophisticated conversion from string to target type
|
||||
list[index] = Convert.ChangeType(nvc[kvp], Nullable.GetUnderlyingType(listItemType) ?? listItemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not initialized - initalize
|
||||
var next = index < list.Count ? list[index] : null;
|
||||
if (next == null)
|
||||
{
|
||||
// handle IList case in a special way here, since you cannot create instance of interface
|
||||
next = Activator.CreateInstance(listItemType);
|
||||
// fill with nulls if not enough items yet
|
||||
while (index >= list.Count)
|
||||
{
|
||||
list.Add(null);
|
||||
}
|
||||
list[index] = next;
|
||||
}
|
||||
currentObject = next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var prop = currentObject.GetType().GetProperty(propName, BindingFlags.Instance | BindingFlags.Public);
|
||||
if (last)
|
||||
{
|
||||
// may need more sophisticated conversion from string to target type
|
||||
prop.SetValue(currentObject, Convert.ChangeType(nvc[kvp], Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not initialized - initalize
|
||||
var next = prop.GetValue(currentObject);
|
||||
if (next == null)
|
||||
{
|
||||
// TODO: handle IList case in a special way here, since you cannot create instance of interface
|
||||
next = Activator.CreateInstance(prop.PropertyType);
|
||||
prop.SetValue(currentObject, next);
|
||||
}
|
||||
currentObject = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user