2019-07-10 17:33:58 -04:00
|
|
|
|
using NUnit.Framework.Constraints;
|
2019-07-24 14:56:34 -04:00
|
|
|
|
using System;
|
2019-09-02 19:10:17 -04:00
|
|
|
|
using Vanara.PInvoke;
|
2019-07-10 17:33:58 -04:00
|
|
|
|
|
|
|
|
|
namespace Vanara.PInvoke.Tests
|
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public abstract class ResultIs // : NUnit.Framework.Is
|
2019-07-10 17:33:58 -04:00
|
|
|
|
{
|
2019-07-11 17:13:00 -04:00
|
|
|
|
public static FailureConstraint Failure => new FailureConstraint();
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public static MyConstraintExpression Not => MyConstraintExpression.Not;
|
2019-07-16 09:43:56 -04:00
|
|
|
|
public static SuccessfulConstraint Successful => new SuccessfulConstraint();
|
2019-07-17 15:58:43 -04:00
|
|
|
|
public static ValidHandleConstraint ValidHandle => new ValidHandleConstraint();
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-24 14:56:34 -04:00
|
|
|
|
public static FailureConstraint FailureCode(object expectedError) => new FailureConstraint(expectedError);
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public static ValueConstraint Value(object value) => new ValueConstraint(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class MyConstraintExpression
|
|
|
|
|
{
|
|
|
|
|
private OpConstraint.Op op;
|
|
|
|
|
|
|
|
|
|
private MyConstraintExpression(OpConstraint.Op _op) => op = _op;
|
|
|
|
|
|
|
|
|
|
public static MyConstraintExpression Not => new MyConstraintExpression(OpConstraint.Op.Not);
|
|
|
|
|
|
|
|
|
|
public ValidHandleConstraint ValidHandle => new ValidHandleConstraint(op);
|
|
|
|
|
|
|
|
|
|
public ValueConstraint Value(object value) => new ValueConstraint(value, op);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class FailureConstraint : Constraint
|
|
|
|
|
{
|
2019-07-24 14:56:34 -04:00
|
|
|
|
public FailureConstraint(object expected = null)
|
2019-07-11 17:13:00 -04:00
|
|
|
|
{
|
2019-07-24 14:56:34 -04:00
|
|
|
|
switch (expected)
|
|
|
|
|
{
|
|
|
|
|
case null:
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case uint i:
|
2019-07-24 14:56:34 -04:00
|
|
|
|
Expected = new Win32Error(i);
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case int i:
|
2019-07-24 14:56:34 -04:00
|
|
|
|
Expected = new HRESULT(i);
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-24 14:56:34 -04:00
|
|
|
|
case IErrorProvider iep:
|
|
|
|
|
Expected = iep;
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-24 14:56:34 -04:00
|
|
|
|
default:
|
|
|
|
|
throw new ArgumentException();
|
|
|
|
|
}
|
2019-07-11 17:13:00 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-24 14:56:34 -04:00
|
|
|
|
public object Expected { get; }
|
|
|
|
|
|
2019-07-11 17:13:00 -04:00
|
|
|
|
public override ConstraintResult ApplyTo<TActual>(TActual actual)
|
|
|
|
|
{
|
|
|
|
|
var success = false;
|
|
|
|
|
object updActual = actual;
|
|
|
|
|
switch (actual)
|
|
|
|
|
{
|
|
|
|
|
case bool b:
|
|
|
|
|
success = b;
|
|
|
|
|
Description = nameof(Win32Error.ERROR_SUCCESS);
|
|
|
|
|
if (!b)
|
|
|
|
|
{
|
|
|
|
|
var le = Win32Error.GetLastError();
|
2019-07-24 14:56:34 -04:00
|
|
|
|
if (Expected != null) Description = Expected.ToString();
|
|
|
|
|
success = Expected is null ? le.Failed : le.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(le.ToHRESULT());
|
2019-07-11 17:13:00 -04:00
|
|
|
|
updActual = le;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HRESULT hr:
|
2019-07-24 14:56:34 -04:00
|
|
|
|
success = Expected is null ? hr.Failed : hr.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(hr);
|
|
|
|
|
Description = Expected?.ToString() ?? nameof(HRESULT.S_OK);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Win32Error err:
|
2019-07-24 14:56:34 -04:00
|
|
|
|
success = Expected is null ? err.Failed : err.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(err.ToHRESULT());
|
|
|
|
|
Description = Expected?.ToString() ?? nameof(Win32Error.ERROR_SUCCESS);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NTStatus st:
|
2019-07-24 14:56:34 -04:00
|
|
|
|
success = Expected is null ? st.Failed : st.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(((IErrorProvider)st).ToHRESULT());
|
|
|
|
|
Description = Expected?.ToString() ?? nameof(NTStatus.STATUS_SUCCESS);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
break;
|
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case uint i:
|
2019-07-11 17:13:00 -04:00
|
|
|
|
var e = new Win32Error(i);
|
2019-07-24 14:56:34 -04:00
|
|
|
|
success = Expected is null ? e.Failed : e.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(e.ToHRESULT());
|
2019-07-11 17:13:00 -04:00
|
|
|
|
updActual = e;
|
2019-07-24 14:56:34 -04:00
|
|
|
|
Description = Expected?.ToString() ?? nameof(Win32Error.ERROR_SUCCESS);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
break;
|
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case int ui:
|
2019-07-11 17:13:00 -04:00
|
|
|
|
var h = new HRESULT(ui);
|
2019-07-24 14:56:34 -04:00
|
|
|
|
success = Expected is null ? h.Failed : h.Failed && ((IErrorProvider)Expected).ToHRESULT().Equals(h);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
updActual = h;
|
2019-07-24 14:56:34 -04:00
|
|
|
|
Description = Expected?.ToString() ?? nameof(HRESULT.S_OK);
|
2019-07-11 17:13:00 -04:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return new ConstraintResult(this, updActual, success);
|
|
|
|
|
}
|
2019-07-10 17:33:58 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SuccessfulConstraint : Constraint
|
|
|
|
|
{
|
|
|
|
|
public SuccessfulConstraint()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override ConstraintResult ApplyTo<TActual>(TActual actual)
|
|
|
|
|
{
|
|
|
|
|
var success = false;
|
2019-09-02 19:10:17 -04:00
|
|
|
|
var updActual = actual as IErrorProvider;
|
2019-07-10 17:33:58 -04:00
|
|
|
|
switch (actual)
|
|
|
|
|
{
|
|
|
|
|
case bool b:
|
|
|
|
|
success = b;
|
|
|
|
|
Description = nameof(Win32Error.ERROR_SUCCESS);
|
|
|
|
|
if (!b)
|
|
|
|
|
{
|
|
|
|
|
var le = Win32Error.GetLastError();
|
|
|
|
|
success = le.Succeeded;
|
|
|
|
|
updActual = le;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HRESULT hr:
|
|
|
|
|
success = hr.Succeeded;
|
|
|
|
|
Description = nameof(HRESULT.S_OK);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Win32Error err:
|
|
|
|
|
success = err.Succeeded;
|
|
|
|
|
Description = nameof(Win32Error.ERROR_SUCCESS);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NTStatus st:
|
|
|
|
|
success = st.Succeeded;
|
|
|
|
|
Description = nameof(NTStatus.STATUS_SUCCESS);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case uint i:
|
2019-07-10 17:33:58 -04:00
|
|
|
|
var e = new Win32Error(i);
|
|
|
|
|
success = e.Succeeded;
|
|
|
|
|
updActual = e;
|
|
|
|
|
Description = nameof(Win32Error.ERROR_SUCCESS);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-04-27 23:25:47 -04:00
|
|
|
|
case int ui:
|
2019-07-10 17:33:58 -04:00
|
|
|
|
var h = new HRESULT(ui);
|
|
|
|
|
success = h.Succeeded;
|
|
|
|
|
updActual = h;
|
|
|
|
|
Description = nameof(HRESULT.S_OK);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return new ConstraintResult(this, updActual, success);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-16 09:43:56 -04:00
|
|
|
|
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public abstract class OpConstraint : Constraint
|
2019-07-16 09:43:56 -04:00
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public enum Op
|
2019-07-16 09:43:56 -04:00
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
None = 0,
|
|
|
|
|
Not = 1
|
2019-07-16 09:43:56 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 16:59:39 -04:00
|
|
|
|
protected Op AppliedOp { get; }
|
|
|
|
|
|
|
|
|
|
protected OpConstraint(Op op) => AppliedOp = op;
|
|
|
|
|
|
|
|
|
|
protected string Prefix
|
2019-07-16 09:43:56 -04:00
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
get
|
2019-07-16 09:43:56 -04:00
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
switch (AppliedOp)
|
|
|
|
|
{
|
|
|
|
|
case Op.Not:
|
|
|
|
|
return "Not ";
|
|
|
|
|
default:
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2019-07-16 09:43:56 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-17 15:58:43 -04:00
|
|
|
|
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public class ValidHandleConstraint : OpConstraint
|
2019-07-17 15:58:43 -04:00
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public ValidHandleConstraint(OpConstraint.Op op = OpConstraint.Op.None) : base(op)
|
2019-07-17 15:58:43 -04:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override ConstraintResult ApplyTo<TActual>(TActual actual)
|
|
|
|
|
{
|
2019-07-26 16:59:39 -04:00
|
|
|
|
IntPtr val;
|
|
|
|
|
bool success;
|
2019-07-17 15:58:43 -04:00
|
|
|
|
switch (actual)
|
|
|
|
|
{
|
|
|
|
|
case System.Runtime.InteropServices.SafeHandle h:
|
|
|
|
|
success = !h.IsInvalid;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
val = h.DangerousGetHandle();
|
2019-07-17 15:58:43 -04:00
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-17 15:58:43 -04:00
|
|
|
|
case IHandle ih:
|
2019-07-26 16:59:39 -04:00
|
|
|
|
val = ih.DangerousGetHandle();
|
|
|
|
|
var l = val.ToInt64();
|
2019-07-17 15:58:43 -04:00
|
|
|
|
success = l != 0 && l != -1;
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-17 15:58:43 -04:00
|
|
|
|
case System.IntPtr p:
|
2019-07-26 16:59:39 -04:00
|
|
|
|
val = p;
|
|
|
|
|
l = val.ToInt64();
|
2019-07-17 15:58:43 -04:00
|
|
|
|
success = l != 0 && l != -1;
|
|
|
|
|
break;
|
2019-07-26 16:59:39 -04:00
|
|
|
|
|
2019-07-17 15:58:43 -04:00
|
|
|
|
default:
|
2019-07-26 16:59:39 -04:00
|
|
|
|
throw new InvalidCastException("Cannot get a handle from value.");
|
2019-07-17 15:58:43 -04:00
|
|
|
|
}
|
|
|
|
|
Description = $"Valid handle";
|
2019-07-26 16:59:39 -04:00
|
|
|
|
if (AppliedOp == Op.Not)
|
|
|
|
|
{
|
|
|
|
|
success = !success;
|
|
|
|
|
Description = $"Invalid handle";
|
|
|
|
|
}
|
|
|
|
|
return new ErrConstraintResult(this, string.Format("0x{0:X" + IntPtr.Size + "}", val.ToInt64()), success);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ValueConstraint : OpConstraint
|
|
|
|
|
{
|
|
|
|
|
public object Expected { get; }
|
|
|
|
|
|
|
|
|
|
public ValueConstraint(object expected, OpConstraint.Op op = OpConstraint.Op.None) : base(op)
|
|
|
|
|
{
|
|
|
|
|
Expected = expected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override ConstraintResult ApplyTo<TActual>(TActual actual)
|
|
|
|
|
{
|
|
|
|
|
var eq = new EqualConstraint(Expected);
|
|
|
|
|
Description = Prefix + eq.Description;
|
|
|
|
|
var success = eq.ApplyTo(actual).IsSuccess;
|
|
|
|
|
if (AppliedOp == Op.Not)
|
|
|
|
|
success = !success;
|
|
|
|
|
return new ErrConstraintResult(this, actual, success);
|
2019-07-17 15:58:43 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 16:59:39 -04:00
|
|
|
|
public class ErrConstraintResult : ConstraintResult
|
|
|
|
|
{
|
|
|
|
|
private readonly Win32Error lastErr;
|
|
|
|
|
|
|
|
|
|
public ErrConstraintResult(IConstraint constraint, object actualValue, bool isSuccessful) : base(constraint, actualValue, isSuccessful)
|
|
|
|
|
{
|
|
|
|
|
lastErr = Win32Error.GetLastError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void WriteAdditionalLinesTo(MessageWriter writer) => writer.Write($" (Err: {lastErr})");
|
|
|
|
|
}
|
2019-07-10 17:33:58 -04:00
|
|
|
|
}
|