<commit_before>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HiddenWallet.KeyManagement;
using HiddenWallet.Models;
using NBitcoin;
using Xunit;
using HiddenWallet.FullSpv;
using HiddenWallet.FullSpv.Fees;
using System.Collections.Specialized;

namespace HiddenWallet.Tests
{
	public class SendTests
	{
		[Fact]
		public async Task SendTestAsync()
		{
			Network network = Network.TestNet;
			SafeAccount account = new SafeAccount(1);
			string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"Sending{network}.json");
			const string password = "";
			Safe safe = await Safe.LoadAsync(password, path);
			Assert.Equal(network, safe.Network);
			Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}");

            // create walletjob
            WalletJob walletJob = new WalletJob();
            await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe, trackDefaultSafe: false, accountsToTrack: account);
            // note some event
            walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged;
            walletJob.StateChanged += WalletJob_StateChanged;

			// start syncing
			var cts = new CancellationTokenSource();
			var walletJobTask = walletJob.StartAsync(cts.Token);
			Task reportTask = Helpers.ReportAsync(cts.Token, walletJob);

			try
			{
                // wait until blocks are synced
                while (walletJob.State <= WalletState.SyncingMemPool)
                {
                    await Task.Delay(1000);
                }

                foreach (var r in await walletJob.GetSafeHistoryAsync(account))
                {
                    Debug.WriteLine(r.TransactionId);
                }

				# region Basic

				var receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();

                var getBalanceResult = await walletJob.GetBalanceAsync(account);
                var bal = getBalanceResult.Available;
                Money amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;
				var res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Contains(res.Transaction.Outputs, x =>x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");
				
				var foundReceive = false;
				Assert.InRange(res.Transaction.Outputs.Count, 1, 2);
				foreach(var output in res.Transaction.Outputs)
				{
					if(output.ScriptPubKey == receive)
					{
						foundReceive = true;
						Assert.Equal(amountToSend, output.Value);
					}
				}
				Assert.True(foundReceive);

				_txProbArrived = false;
				_prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count;
                _currentWalletJob = walletJob;
                (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync;

				var sendRes = await walletJob.SendTransactionAsync(res.Transaction);
				Assert.True(sendRes.Success);
				Assert.Empty(sendRes.FailingReason);

				while (!_txProbArrived)
				{
					Debug.WriteLine("Waiting for transaction...");
					await Task.Delay(1000);
				}

				Debug.WriteLine("TrackedTransactions collection changed");
				Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash());
				Debug.WriteLine("Transaction arrived");


				receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();

				bal = (await walletJob.GetBalanceAsync(account)).Available;
				amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;

				#endregion

				#region LowFee

				res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");

				foundReceive = false;<commit_msg>add test for customchange<commit_after>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HiddenWallet.KeyManagement;
using HiddenWallet.Models;
using NBitcoin;
using Xunit;
using HiddenWallet.FullSpv;
using HiddenWallet.FullSpv.Fees;
using System.Collections.Specialized;

namespace HiddenWallet.Tests
{
	public class SendTests
	{
		[Fact]
		public async Task SendTestAsync()
		{
			Network network = Network.TestNet;
			SafeAccount account = new SafeAccount(1);
			string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"Sending{network}.json");
			const string password = "";
			Safe safe = await Safe.LoadAsync(password, path);
			Assert.Equal(network, safe.Network);
			Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}");

            // create walletjob
            WalletJob walletJob = new WalletJob();
            await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe, trackDefaultSafe: false, accountsToTrack: account);
            // note some event
            walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged;
            walletJob.StateChanged += WalletJob_StateChanged;

			// start syncing
			var cts = new CancellationTokenSource();
			var walletJobTask = walletJob.StartAsync(cts.Token);
			Task reportTask = Helpers.ReportAsync(cts.Token, walletJob);

			try
			{
                // wait until blocks are synced
                while (walletJob.State <= WalletState.SyncingMemPool)
                {
                    await Task.Delay(1000);
                }

                foreach (var r in await walletJob.GetSafeHistoryAsync(account))
                {
                    Debug.WriteLine(r.TransactionId);
                }

				# region Basic

				var receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();

                var getBalanceResult = await walletJob.GetBalanceAsync(account);
                var bal = getBalanceResult.Available;
                Money amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;
				var res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Contains(res.Transaction.Outputs, x =>x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");
				
				var foundReceive = false;
				Assert.InRange(res.Transaction.Outputs.Count, 1, 2);
				foreach(var output in res.Transaction.Outputs)
				{
					if(output.ScriptPubKey == receive)
					{
						foundReceive = true;
						Assert.Equal(amountToSend, output.Value);
					}
				}
				Assert.True(foundReceive);

				_txProbArrived = false;
				_prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count;
                _currentWalletJob = walletJob;
                (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync;

				var sendRes = await walletJob.SendTransactionAsync(res.Transaction);
				Assert.True(sendRes.Success);
				Assert.Empty(sendRes.FailingReason);

				while (!_txProbArrived)
				{
					Debug.WriteLine("Waiting for transaction...");
					await Task.Delay(1000);
				}

				Debug.WriteLine("TrackedTransactions collection changed");
				Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash());
				Debug.WriteLine("Transaction arrived");


				receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();

				bal = (await walletJob.GetBalanceAsync(account)).Available;
				amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;

				#endregion

				#region SubtractFeeFromAmount

				receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();

				getBalanceResult = await walletJob.GetBalanceAsync(account);
				bal = getBalanceResult.Available;
				amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;
				res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true,
					subtractFeeFromAmount: true);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend - res.Fee, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");

				foundReceive = false;
				Assert.InRange(res.Transaction.Outputs.Count, 1, 2);
				foreach (var output in res.Transaction.Outputs)
				{
					if (output.ScriptPubKey == receive)
					{
						foundReceive = true;
						Assert.Equal(amountToSend - res.Fee, output.Value);
					}
				}
				Assert.True(foundReceive);
				
				#endregion

				#region CustomChange

				receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault();
				var customChange = new Key().ScriptPubKey;

				getBalanceResult = await walletJob.GetBalanceAsync(account);
				bal = getBalanceResult.Available;
				amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2;
				res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true,
					subtractFeeFromAmount: true,
					customChangeScriptPubKey: customChange);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend - res.Fee, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Equal(customChange, res.ChangeOutput.ScriptPubKey);
				Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");

				foundReceive = false;
				Assert.InRange(res.Transaction.Outputs.Count, 1, 2);
				foreach (var output in res.Transaction.Outputs)
				{
					if (output.ScriptPubKey == receive)
					{
						foundReceive = true;
						Assert.Equal(amountToSend - res.Fee, output.Value);
					}
				}
				Assert.True(foundReceive);

				#endregion

				#region LowFee

				res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account,
					allowUnconfirmed: true);

				Assert.True(res.Success);
				Assert.Empty(res.FailingReason);
				Assert.Equal(receive, res.ActiveOutput.ScriptPubKey);
				Assert.Equal(amountToSend, res.ActiveOutput.Value);
				Assert.NotNull(res.ChangeOutput);
				Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value);
				Debug.WriteLine($"Fee: {res.Fee}");
				Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %");
				Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}");
				Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}");
				Debug.WriteLine($"TxId: {res.Transaction.GetHash()}");

				foundReceive = false;
{'fraction_non_alphanumeric': 0.11941918849233274, 'fraction_numerical': 0.002578368842448093, 'mean_word_length': 3.99966078697422, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2466151', 'n_tokens_mistral': 5037, 'n_tokens_neox': 4266, 'n_words': 716}