Replace a few poor man's mocks with Moq's mocks
MODIFY
WalletWasabi.Tests/Helpers/ServiceFactory.cs
WalletWasabi.Tests/Helpers/ServiceFactory.cs
+using Moq;
using NBitcoin;
using System;
using System.Collections.Generic;
@@ -40,8 +41,8 @@ namespace WalletWasabi.Tests.Helpers
}
}
var coinsView = new CoinsView(scoins);
- var transactionStore = new AllTransactionStoreMock(workFolderPath: ".", Network.Main);
- return new TransactionFactory(Network.Main, keyManager, coinsView, transactionStore, password, allowUnconfirmed);
+ var mockTransactionStore = new Mock<AllTransactionStore>(".", Network.Main);
+ return new TransactionFactory(Network.Main, keyManager, coinsView, mockTransactionStore.Object, password, allowUnconfirmed);
}
public static KeyManager CreateKeyManager(string password = "blahblahblah")

MODIFY
WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
@@ -148,7 +148,6 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(5, any)).ReturnsAsync(FeeRateResponse(5, 89m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(6, any)).ReturnsAsync(FeeRateResponse(6, 75m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(8, any)).ReturnsAsync(FeeRateResponse(8, 70m));
-
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsNotIn<int>(2, 3, 5, 6, 8), any)).ThrowsAsync(new NoEstimationException(0));
var allFee = await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
@@ -162,7 +161,7 @@ namespace WalletWasabi.Tests.UnitTests
public async Task InaccurateEstimationsAsync()
{
var mockRpc = CreateAndConfigureRpcClient(isSynchronized: false, hasPeersInfo: true);
- var any = It.IsAny<EstimateSmartFeeMode>();
+ var any = EstimateSmartFeeMode.Economical;
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(2, any)).ReturnsAsync(FeeRateResponse(2, 100m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(3, any)).ReturnsAsync(FeeRateResponse(3, 100m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(5, any)).ReturnsAsync(FeeRateResponse(5, 89m));

DELETE
WalletWasabi.Tests/UnitTests/Clients/MockTorHttpClient.cs
-using System;
-using System.Collections.Specialized;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Web;
-using WalletWasabi.Tor.Http;
-
-namespace WalletWasabi.Tests.UnitTests.Clients
-{
- public class MockTorHttpClient : IHttpClient
- {
- public Func<Uri> BaseUriGetter => () => new Uri("https://payment.server.org/pj");
-
- public Func<HttpMethod, string, NameValueCollection, string, Task<HttpResponseMessage>> OnSendAsync { get; set; }
-
- public async Task<HttpResponseMessage> SendAsync(HttpMethod method, string relativeUri, HttpContent? content = null, CancellationToken cancel = default)
- {
- string body = (content is { })
- ? await content.ReadAsStringAsync(cancel).ConfigureAwait(false)
- : "";
-
- // It does not matter which URI is actually used here, we just need to construct absolute URI to be able to access `uri.Query`.
- Uri baseUri = new Uri("http://127.0.0.1");
- Uri uri = new Uri(baseUri, relativeUri);
- NameValueCollection parameters = HttpUtility.ParseQueryString(uri.Query);
-
- return await OnSendAsync(method, uri.AbsolutePath, parameters, body).ConfigureAwait(false);
- }
-
- public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken token = default)
- {
- string body = (request.Content is { })
- ? await request.Content.ReadAsStringAsync(token).ConfigureAwait(false)
- : "";
-
- Uri uri = request.RequestUri!;
- NameValueCollection parameters = HttpUtility.ParseQueryString(uri.Query);
-
- return await OnSendAsync(request.Method, uri.AbsolutePath, parameters, body).ConfigureAwait(false);
- }
- }
-}

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/CredentialIssuerKeyTests.cs
WalletWasabi.Tests/UnitTests/Crypto/CredentialIssuerKeyTests.cs
+using Moq;
using NBitcoin.Secp256k1;
using System;
using System.Linq;
@@ -14,32 +15,38 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
public void GenerateCredentialIssuerParameters()
{
// Coordinator key is (0, 0, 0, 0, 0)
- var rnd = new MockRandom();
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 5));
- var key = new CredentialIssuerSecretKey(rnd);
+ var mockRandom = new Mock<WasabiRandom>();
+ mockRandom.Setup(rnd => rnd.GetScalar(true)).Returns(Scalar.Zero);
+ var key = new CredentialIssuerSecretKey(mockRandom.Object);
var ex = Assert.Throws<ArgumentException>(key.ComputeCredentialIssuerParameters);
Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);
// Coordinator key is (0, 0, 1, 1, 1)
- rnd = new MockRandom();
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 2));
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 3));
- key = new CredentialIssuerSecretKey(rnd);
+ mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
+ .Returns(Scalar.Zero)
+ .Returns(Scalar.Zero)
+ .Returns(Scalar.One)
+ .Returns(Scalar.One)
+ .Returns(Scalar.One);
+ key = new CredentialIssuerSecretKey(mockRandom.Object);
ex = Assert.Throws<ArgumentException>(key.ComputeCredentialIssuerParameters);
Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);
// Coordinator key is (1, 1, 0, 0, 0)
- rnd = new MockRandom();
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 2));
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 3));
- key = new CredentialIssuerSecretKey(rnd);
+ mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
+ .Returns(Scalar.One)
+ .Returns(Scalar.One)
+ .Returns(Scalar.Zero)
+ .Returns(Scalar.Zero)
+ .Returns(Scalar.Zero);
+ key = new CredentialIssuerSecretKey(mockRandom.Object);
var iparams = key.ComputeCredentialIssuerParameters();
Assert.Equal(Generators.GV, iparams.I);
// Coordinator key is (1, 1, 1, 1, 1)
- rnd = new MockRandom();
- rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 5));
- key = new CredentialIssuerSecretKey(rnd);
+ mockRandom.Setup(rnd => rnd.GetScalar(true))
+ .Returns(Scalar.One);
+ key = new CredentialIssuerSecretKey(mockRandom.Object);
iparams = key.ComputeCredentialIssuerParameters();
Assert.Equal(Generators.Gw + Generators.Gwp, iparams.Cw);
Assert.Equal(Generators.GV - Generators.Gx0 - Generators.Gx1 - Generators.Ga, iparams.I);

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/RandomTests.cs
WalletWasabi.Tests/UnitTests/Crypto/RandomTests.cs
@@ -49,7 +49,6 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
{
new SecureRandom(),
new InsecureRandom(),
- new MockRandom()
};
foreach (var random in randoms)
@@ -58,14 +57,11 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
Assert.Throws<ArgumentOutOfRangeException>(() => random.GetBytes(-1));
Assert.Throws<ArgumentOutOfRangeException>(() => random.GetBytes(0));
- if (random is MockRandom == false)
- {
var r1 = random.GetBytes(1);
Assert.Single(r1);
var r2 = random.GetBytes(2);
Assert.Equal(2, r2.Length);
}
- }
foreach (WasabiRandom random in randoms)
{

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/TranscriptTests.cs
WalletWasabi.Tests/UnitTests/Crypto/TranscriptTests.cs
+using Moq;
using NBitcoin.Secp256k1;
using System;
using System.Linq;
@@ -97,11 +98,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
// if all synthetic nonce provider get the same randomness, nonce sequences
// with different witnesses or commitments should still diverge
- var rnd = new MockRandom();
- rnd.GetBytesResults.Add(new byte[32]);
- rnd.GetBytesResults.Add(new byte[32]);
- rnd.GetBytesResults.Add(new byte[32]);
- rnd.GetBytesResults.Add(new byte[32]);
+ var mockRandom = new Mock<WasabiRandom>();
+ mockRandom.Setup(rnd => rnd.GetBytes(32)).Returns(new byte[32]);
var commitment1 = new[] { Generators.Gx0 };
var commitment2 = new[] { Generators.Gx1 };
@@ -118,13 +116,12 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
transcript3.CommitPublicNonces(commitment2);
transcript4.CommitPublicNonces(commitment2);
+ var rnd = mockRandom.Object;
var secretNonceGenerator1 = transcript1.CreateSyntheticSecretNonceProvider(witness1, rnd);
var secretNonceGenerator2 = transcript2.CreateSyntheticSecretNonceProvider(witness1, rnd);
var secretNonceGenerator3 = transcript3.CreateSyntheticSecretNonceProvider(witness2, rnd);
var secretNonceGenerator4 = transcript4.CreateSyntheticSecretNonceProvider(witness2, rnd);
- Assert.Empty(rnd.GetBytesResults);
-
var secretNonce1 = secretNonceGenerator1.GetScalar();
var secretNonce2 = secretNonceGenerator2.GetScalar();
var secretNonce3 = secretNonceGenerator3.GetScalar();

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfDlogTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfDlogTests.cs
+using Moq;
using NBitcoin.Secp256k1;
using WalletWasabi.Crypto.Groups;
using WalletWasabi.Crypto.Randomness;
@@ -24,9 +25,9 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var generator = Generators.G;
var publicPoint = secret * generator;
var statement = new Statement(publicPoint, generator);
- var random = new MockRandom();
- random.GetBytesResults.Add(new byte[32]);
- var proof = ProofSystemHelpers.Prove(statement, secret, random);
+ var mockRandom = new Mock<WasabiRandom>();
+ mockRandom.Setup(rnd => rnd.GetBytes(32)).Returns(new byte[32]);
+ var proof = ProofSystemHelpers.Prove(statement, secret, mockRandom.Object);
Assert.True(ProofSystemHelpers.Verify(statement, proof));
}

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepTests.cs
+using Moq;
using NBitcoin.Secp256k1;
using System;
using System.Linq;
@@ -29,9 +30,9 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var publicPoint = secrets * generators;
var statement = new Statement(publicPoint, generators);
- var random = new MockRandom();
- random.GetBytesResults.Add(new byte[32]);
- var proof = ProofSystemHelpers.Prove(statement, secrets, random);
+ var mockRandom = new Mock<WasabiRandom>();
+ mockRandom.Setup(rnd => rnd.GetBytes(32)).Returns(new byte[32]);
+ var proof = ProofSystemHelpers.Prove(statement, secrets, mockRandom.Object);
Assert.True(ProofSystemHelpers.Verify(statement, proof));
}

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/PayjoinTests.cs
WalletWasabi.Tests/UnitTests/Transactions/PayjoinTests.cs
@@ -12,6 +12,9 @@ using System.Net;
using System.Text;
using System.Collections.Specialized;
using WalletWasabi.Tests.Helpers;
+using Moq;
+using WalletWasabi.Tor.Http;
+using System.Threading;
namespace WalletWasabi.Tests.UnitTests.Transactions
{
@@ -40,24 +43,22 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
return new OutPoint(RandomUtils.GetUInt256(), 0);
}
- private static Func<HttpMethod, string, NameValueCollection, string, Task<HttpResponseMessage>> PayjoinServerOk(Func<PSBT, PSBT> transformPsbt, HttpStatusCode statusCode = HttpStatusCode.OK)
- => new Func<HttpMethod, string, NameValueCollection, string, Task<HttpResponseMessage>>((method, path, parameters, requestBody) =>
+ private static async Task<HttpResponseMessage> PayjoinServerOk(HttpRequestMessage request, Func<PSBT, PSBT> transformPsbt, HttpStatusCode statusCode = HttpStatusCode.OK)
{
- var psbt = PSBT.Parse(requestBody, Network.Main);
+ var body = await request.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var psbt = PSBT.Parse(body, Network.Main);
var newPsbt = transformPsbt(psbt);
var message = new HttpResponseMessage(statusCode);
message.Content = new StringContent(newPsbt.ToHex(), Encoding.UTF8, "text/plain");
- return Task.FromResult(message);
- });
+ return message;
+ }
- private static Func<HttpMethod, string, NameValueCollection, string, Task<HttpResponseMessage>> PayjoinServerError(HttpStatusCode statusCode, string errorCode, string description = "")
- => new Func<HttpMethod, string, NameValueCollection, string, Task<HttpResponseMessage>>((method, path, parameters, requestBody) =>
+ private static async Task<HttpResponseMessage> PayjoinServerError(HttpRequestMessage request, HttpStatusCode statusCode, string errorCode, string description = "") =>
+ new HttpResponseMessage(statusCode)
{
- var message = new HttpResponseMessage(statusCode);
- message.ReasonPhrase = "";
- message.Content = new StringContent("{ \"errorCode\": \"" + errorCode + "\", \"message\": \"" + description + "\"}");
- return Task.FromResult(message);
- });
+ ReasonPhrase = "",
+ Content = new StringContent("{ \"errorCode\": \"" + errorCode + "\", \"message\": \"" + description + "\"}")
+ };
[Fact]
public void ApplyOptionalParametersTest()
@@ -78,11 +79,11 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
// This tests the scenario where the payjoin server returns the same
// transaction that we sent to it and adds no inputs. This can give
// us the fake sense of privacy but it should be valid.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt => psbt)
- };
- var payjoinClient = NewPayjoinClient(httpClient);
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt => psbt));
+
+ var payjoinClient = NewPayjoinClient(mockHttpClient.Object);
var transactionFactory = ServiceFactory.CreateTransactionFactory(new[]
{
("Pablo", 0, 0.1m, confirmed: true, anonymitySet: 1)
@@ -108,9 +109,9 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
var amountToPay = Money.Coins(0.001m);
// This tests the scenario where the payjoin server behaves as expected.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var clientTx = psbt.ExtractTransaction();
foreach (var input in clientTx.Inputs)
@@ -128,9 +129,9 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
serverCoinToSign.Sign(serverCoinKey);
serverCoinToSign.FinalizeInput();
return newPsbt;
- })
- };
- var payjoinClient = NewPayjoinClient(httpClient);
+ }));
+
+ var payjoinClient = NewPayjoinClient(mockHttpClient.Object);
var transactionFactory = ServiceFactory.CreateTransactionFactory(new[]
{
("Pablo", 0, 0.1m, confirmed: true, anonymitySet: 1)
@@ -180,9 +181,9 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
var payment = new PaymentIntent(BitcoinFactory.CreateScript(), amountToPay);
// This tests the scenario where the payjoin server wants to make us sign one of our own inputs!!!!!.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var newCoin = psbt.Inputs[0].GetCoin();
if (newCoin is { })
@@ -191,11 +192,10 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
psbt.AddCoins(newCoin);
}
return psbt;
- })
- };
+ }));
var transactionFactory = ServiceFactory.CreateTransactionFactory(walletCoins);
- var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
///////
@@ -204,9 +204,8 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
payment = new PaymentIntent(destination, amountToPay);
// This tests the scenario where the payjoin server wants to make us sign one of our own inputs!!!!!.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
var diff = Money.Coins(0.0007m);
@@ -216,10 +215,9 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
paymentOutput.Value += diff;
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
}
@@ -231,139 +229,122 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
var payment = new PaymentIntent(BitcoinFactory.CreateScript(), amountToPay);
// This tests the scenario where the payjoin server does not clean GloablXPubs.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var extPubkey = new ExtKey().Neuter().GetWif(Network.Main);
psbt.GlobalXPubs.Add(extPubkey, new RootedKeyPath(extPubkey.GetPublicKey().GetHDFingerPrint(), KeyManager.DefaultAccountKeyPath));
return psbt;
- })
- };
+ }));
var transactionFactory = ServiceFactory.CreateTransactionFactory(walletCoins);
- var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server includes keypath info in the inputs.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var extPubkey = new ExtKey().Neuter().GetWif(Network.Main);
psbt.Inputs[0].AddKeyPath(new Key().PubKey, new RootedKeyPath(extPubkey.GetPublicKey().GetHDFingerPrint(), KeyManager.DefaultAccountKeyPath));
return psbt;
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server modifies the inputs sequence.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
globalTx.Inputs[0].Sequence = globalTx.Inputs[0].Sequence + 1;
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server returns an unsigned input (fucking bastard).
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
globalTx.Inputs.Add(GetRandomOutPoint());
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server removes one of our inputs (probably to optimize it).
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
globalTx.Inputs.Clear(); // remove all the inputs
globalTx.Inputs.Add(GetRandomOutPoint());
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server includes keypath info in the outputs.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var extPubkey = new ExtKey().Neuter().GetWif(Network.Main);
psbt.Outputs[0].AddKeyPath(new Key().PubKey, new RootedKeyPath(extPubkey.GetPublicKey().GetHDFingerPrint(), KeyManager.DefaultAccountKeyPath));
return psbt;
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server includes partial signatures.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var extPubkey = new ExtKey().Neuter().GetWif(Network.Main);
psbt.Inputs[0].PartialSigs.Add(new Key().PubKey, new TransactionSignature(new Key().Sign(uint256.One)));
return psbt;
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server modifies the original tx version.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
globalTx.Version += 1;
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
////////
// This tests the scenario where the payjoin server modifies the original tx locktime value.
- httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
globalTx.LockTime = new LockTime(globalTx.LockTime + 1);
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
- tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
}
@@ -377,19 +358,18 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
var payment = new PaymentIntent(destination, amountToPay);
// This tests the scenario where the payjoin server wants to make us sign one of our own inputs!!!!!.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerOk(psbt =>
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerOk(req, psbt =>
{
var globalTx = psbt.GetGlobalTransaction();
var changeOutput = globalTx.Outputs.Single(x => x.ScriptPubKey != destination);
changeOutput.Value -= Money.Coins(0.0007m);
return PSBT.FromTransaction(globalTx, Network.Main);
- })
- };
+ }));
var transactionFactory = ServiceFactory.CreateTransactionFactory(walletCoins);
- var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
}
@@ -402,17 +382,16 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
var payment = new PaymentIntent(BitcoinFactory.CreateScript(), amountToPay);
// This tests the scenario where the payjoin server wants to make us sign one of our own inputs!!!!!.
- var httpClient = new MockTorHttpClient
- {
- OnSendAsync = PayjoinServerError(statusCode: HttpStatusCode.InternalServerError, "Internal Server Error")
- };
+ var mockHttpClient = new Mock<IHttpClient>();
+ mockHttpClient.Setup(http => http.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()) )
+ .Returns((HttpRequestMessage req, CancellationToken _) => PayjoinServerError(req, HttpStatusCode.InternalServerError, "-2345", "Internal Server Error"));
var transactionFactory = ServiceFactory.CreateTransactionFactory(walletCoins);
- var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(httpClient));
+ var tx = transactionFactory.BuildTransaction(payment, new FeeRate(2m), transactionFactory.Coins.Select(x => x.OutPoint), NewPayjoinClient(mockHttpClient.Object));
Assert.Single(tx.Transaction.Transaction.Inputs);
}
- private static PayjoinClient NewPayjoinClient(MockTorHttpClient client)
- => new PayjoinClient(client.BaseUriGetter.Invoke(), client);
+ private static PayjoinClient NewPayjoinClient(IHttpClient client)
+ => new PayjoinClient(new Uri("http://localhost"), client);
}
}

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/TransactionFactoryTests.cs
WalletWasabi.Tests/UnitTests/Transactions/TransactionFactoryTests.cs
+using Moq;
using NBitcoin;
using System;
using System.Linq;
@@ -218,8 +219,8 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
}
var coinsView = new CoinsView(scoins.ToArray());
- await using var transactionStore = new AllTransactionStoreMock(workFolderPath: ".", Network.Main);
- var transactionFactory = new TransactionFactory(Network.Main, keyManager, coinsView, transactionStore, password);
+ var mockTransactionStore = new Mock<AllTransactionStore>(".", Network.Main);
+ var transactionFactory = new TransactionFactory(Network.Main, keyManager, coinsView, mockTransactionStore.Object, password);
// Two 0.9btc coins are enough
using Key key1 = new Key();

DELETE
WalletWasabi.Tests/UnitTests/Transactions/TransactionStoreMock.cs
-using NBitcoin;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using System.Threading.Tasks;
-using WalletWasabi.Blockchain.Transactions;
-using WalletWasabi.Tests.Helpers;
-
-namespace WalletWasabi.Tests.UnitTests.Transactions
-{
- public class TransactionStoreMock : TransactionStore
- {
- public TransactionStoreMock([CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "")
- {
- // Make sure starts with clear state.
- var filePath = Path.Combine(Common.GetWorkDir(callerFilePath, callerMemberName), "Transactions.dat");
- if (File.Exists(filePath))
- {
- File.Delete(filePath);
- }
- }
-
- public async Task InitializeAsync(Network network, [CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "")
- {
- var dir = Path.Combine(Common.GetWorkDir(callerFilePath, callerMemberName));
- await InitializeAsync(dir, network, $"{nameof(TransactionStoreMock)}.{nameof(TransactionStoreMock.InitializeAsync)}", CancellationToken.None);
- }
- }
-}

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/TransactionStoreTests.cs
WalletWasabi.Tests/UnitTests/Transactions/TransactionStoreTests.cs
using NBitcoin;
using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Blockchain.Transactions;
using WalletWasabi.Tests.Helpers;
@@ -12,11 +14,9 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
[Fact]
public async Task CanInitializeAsync()
{
- await using var txStore = new TransactionStoreMock();
- var network = Network.Main;
- await txStore.InitializeAsync(network);
+ var txStore = await CreateTransactionStoreAsync();
- Assert.Equal(network, txStore.Network);
+ Assert.Equal(Network.Main, txStore.Network);
Assert.Empty(txStore.GetTransactionHashes());
Assert.Empty(txStore.GetTransactions());
Assert.True(txStore.IsEmpty());
@@ -29,9 +29,7 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
[Fact]
public async Task CanDoOperationsAsync()
{
- await using var txStore = new TransactionStoreMock();
- var network = Network.Main;
- await txStore.InitializeAsync(network);
+ var txStore = await CreateTransactionStoreAsync();
Assert.True(txStore.IsEmpty());
@@ -79,5 +77,19 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
Assert.Single(txStore.GetTransactions());
Assert.Single(txStore.GetTransactionHashes());
}
+
+ private static async Task<TransactionStore> CreateTransactionStoreAsync([CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "")
+ {
+ // Make sure starts with clear state.
+ var dir = Path.Combine(Common.GetWorkDir(callerFilePath, callerMemberName));
+ var filePath = Path.Combine(dir, "Transactions.dat");
+ if (File.Exists(filePath))
+ {
+ File.Delete(filePath);
+ }
+ var txStore = new TransactionStore();
+ await txStore.InitializeAsync(dir, Network.Main, $"{nameof(TransactionStore)}.{nameof(TransactionStore.InitializeAsync)}", CancellationToken.None);
+ return txStore;
+ }
}
}

DELETE
WalletWasabi/Blockchain/Transactions/AllTransactionStoreMock.cs
-using NBitcoin;
-
-namespace WalletWasabi.Blockchain.Transactions
-{
- public class AllTransactionStoreMock : AllTransactionStore
- {
- public AllTransactionStoreMock(string workFolderPath, Network network) : base(workFolderPath, network)
- {
- }
-
- public override bool TryGetTransaction(uint256 hash, out SmartTransaction sameStx)
- {
- sameStx = null;
- return false;
- }
- }
-}

MODIFY
WalletWasabi/Crypto/Randomness/MockRandom.cs
WalletWasabi/Crypto/Randomness/MockRandom.cs
@@ -8,14 +8,6 @@ namespace WalletWasabi.Crypto.Randomness
public class MockRandom : WasabiRandom
{
public List<byte[]> GetBytesResults { get; } = new List<byte[]>();
- public List<Scalar> GetScalarResults { get; } = new List<Scalar>();
-
- public override void GetBytes(byte[] output)
- {
- var first = GetBytesResults.First();
- GetBytesResults.RemoveFirst();
- Buffer.BlockCopy(first, 0, output, 0, first.Length);
- }
public override void GetBytes(Span<byte> output)
{
@@ -24,23 +16,14 @@ namespace WalletWasabi.Crypto.Randomness
first.AsSpan().CopyTo(output);
}
- public override int GetInt(int fromInclusive, int toExclusive)
+ public override void GetBytes(byte[] output)
{
throw new NotImplementedException();
}
- public override Scalar GetScalar(bool allowZero = true)
- {
- if (GetScalarResults.Any())
- {
- var first = GetScalarResults.First();
- GetScalarResults.RemoveFirst();
- return first;
- }
- else
+ public override int GetInt(int fromInclusive, int toExclusive)
{
- return base.GetScalar(allowZero);
- }
+ throw new NotImplementedException();
}
}
}

MODIFY
WalletWasabi/Crypto/Randomness/WasabiRandom.cs
WalletWasabi/Crypto/Randomness/WasabiRandom.cs
@@ -12,7 +12,7 @@ namespace WalletWasabi.Crypto.Randomness
public abstract void GetBytes(Span<byte> output);
- public byte[] GetBytes(int length)
+ public virtual byte[] GetBytes(int length)
{
Guard.MinimumAndNotNull(nameof(length), length, 1);
var buffer = new byte[length];

Replace a few poor man's mocks with Moq's mocks