Newer
Older
"""
Copyright 2016-2020 Maël Azimi <m.a@moul.re>
Silkaj is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Silkaj is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
"""
from click.testing import CliRunner
from silkaj import tx
from silkaj.money import UDValue
from silkaj.cli import cli
from silkaj.constants import (
MINIMAL_ABSOLUTE_TX_AMOUNT,
MINIMAL_RELATIVE_TX_AMOUNT,
FAILURE_EXIT_STATUS,
CENT_MULT_TO_UNIT,
)
from patched.money import patched_ud_value, patched_get_sources
from patched.test_constants import mock_ud_value
from patched.auth import patched_auth_method
from patched.tx import patched_transaction_confirmation
# AsyncMock available from Python 3.8. asynctest is used for Py < 3.8
if sys.version_info[1] > 7:
from unittest.mock import AsyncMock
else:
from asynctest.mock import CoroutineMock as AsyncMock
# create test auths
@pass_context
def patched_auth_method_truc(ctx):
return patched_auth_method("truc")
@pass_context
def patched_auth_method_riri(ctx):
return patched_auth_method("riri")
@pytest.mark.asyncio
async def test_transaction_amount(monkeypatch):
"""test passed amounts passed tx command
float ≠ 100 does not give the exact value"""
monkeypatch.setattr(UDValue, "get_ud_value", patched_ud_value)
trials = (
# tests for --amount (unit)
([141.89], None, ["A"], [14189]),
([141.99], None, ["A"], [14199]),
([141.01], None, ["A"], [14101]),
([141.89], None, ["A", "B"], [14189, 14189]),
([141.89, 141.99], None, ["A", "B"], [14189, 14199]),
# tests for --amount_UD
(None, [1.1], ["A"], [round(1.1 * mock_ud_value)]),
(
None,
[1.9],
[
"A",
"B",
],
[round(1.9 * mock_ud_value), round(1.9 * mock_ud_value)],
),
(None, [1.0001], ["A"], [round(1.0001 * mock_ud_value)]),
(None, [9.9999], ["A"], [round(9.9999 * mock_ud_value)]),
(
None,
[1.9, 2.3],
["A", "B"],
[round(1.9 * mock_ud_value), round(2.3 * mock_ud_value)],
for trial in trials:
assert trial[3] == await tx.transaction_amount(trial[0], trial[1], trial[2])
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# transaction_amount errors()
@pytest.mark.parametrize(
"amounts, UDs_amounts, outputAddresses, expected",
[
(
None,
[0.00002],
["DBM6F5ChMJzpmkUdL5zD9UXKExmZGfQ1AgPDQy4MxSBw"],
"Error: amount 0.00002 is too low.",
),
(
[10, 56],
None,
["DBM6F5ChMJzpmkUdL5zD9UXKExmZGfQ1AgPDQy4MxSBw"],
"Error: The number of passed recipients is not the same as the passed amounts.",
),
(
None,
[1, 45],
["DBM6F5ChMJzpmkUdL5zD9UXKExmZGfQ1AgPDQy4MxSBw"],
"Error: The number of passed recipients is not the same as the passed amounts.",
),
],
)
@pytest.mark.asyncio
async def test_transaction_amount_errors(
amounts, UDs_amounts, outputAddresses, expected, capsys, monkeypatch
):
# patched functions
monkeypatch.setattr("silkaj.money.UDValue.get_ud_value", patched_ud_value)
def too_little_amount(amounts, multiplicator):
for amount in amounts:
if amount * multiplicator < MINIMAL_ABSOLUTE_TX_AMOUNT * CENT_MULT_TO_UNIT:
return True
return False
# run tests
if amounts:
given_amounts = amounts
if UDs_amounts:
given_amounts = UDs_amounts
# check program exit on error
with pytest.raises(SystemExit) as pytest_exit:
# read output to check error.
await tx.transaction_amount(amounts, UDs_amounts, outputAddresses)
assert expected == capsys.readouterr()
assert pytest_exit.type == SystemExit
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def test_tx_passed_amount_cli():
"""One option"""
result = CliRunner().invoke(cli, ["tx", "--amount", "1"])
assert "Error: Missing option" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "--amountUD", "1"])
assert "Error: Missing option" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "--allSources"])
assert "Error: Missing option" in result.output
assert result.exit_code == 2
"""Multiple options"""
result = CliRunner().invoke(cli, ["tx", "--amount", 1, "--amountUD", 1])
assert "Error: Usage" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "--amount", 1, "--allSources"])
assert "Error: Usage" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "--amountUD", 1, "--allSources"])
assert "Error: Usage" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(
cli, ["tx", "--amount", 1, "--amountUD", 1, "--allSources"]
)
assert "Error: Usage" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "-r", "A"])
assert "Error: amount, amountUD or allSources is not set." in result.output
assert result.exit_code == FAILURE_EXIT_STATUS
result = CliRunner().invoke(cli, ["tx", "-r", "A", "-r", "B", "--allSources"])
assert (
"Error: the --allSources option can only be used with one recipient."
in result.output
)
assert result.exit_code == FAILURE_EXIT_STATUS
result = CliRunner().invoke(
cli, ["tx", "-r", "A", "-a", MINIMAL_ABSOLUTE_TX_AMOUNT - 0.001]
)
assert "Error: Invalid value for '--amount'" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(
cli, ["tx", "-r", "A", "-d", MINIMAL_RELATIVE_TX_AMOUNT - 0.0000001]
)
assert "Error: Invalid value for '--amountUD'" in result.output
assert result.exit_code == 2
result = CliRunner().invoke(cli, ["tx", "-r", "A", "-a", 1, "-a", 2])
assert (
"Error: The number of passed recipients is not the same as the passed amounts."
in result.output
)
assert result.exit_code == FAILURE_EXIT_STATUS
result = CliRunner().invoke(
cli, ["tx", "-r", "A", "-r", "B", "-r", "C", "-a", 1, "-a", 2]
)
assert (
"Error: The number of passed recipients is not the same as the passed amounts."
in result.output
)
assert result.exit_code == FAILURE_EXIT_STATUS
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
@pytest.mark.parametrize(
"arguments, auth_method, is_account_filled",
[
(["tx", "--allSources", "-r", "A" * 43], patched_auth_method_truc, False),
(["tx", "--allSources", "-r", "A" * 43], patched_auth_method_riri, True),
],
)
def test_tx_passed_all_sources_empty(
arguments, auth_method, is_account_filled, monkeypatch
):
"""test that --allSources on an empty pubkey returns an error"""
# patch functions
monkeypatch.setattr("silkaj.auth.auth_method", auth_method)
monkeypatch.setattr("silkaj.money.get_sources", patched_get_sources)
patched_transaction_confirmation = AsyncMock()
monkeypatch.setattr(
"silkaj.tx.transaction_confirmation", patched_transaction_confirmation
)
result = CliRunner().invoke(cli, args=arguments)
# test error
if not is_account_filled:
assert (
"Error: Issuer pubkey FA4uAQ92rmxidQPgtMopaLfNNzhxu7wLgUsUkqKkSwPr:4E7 is empty. No transaction sent."
in result.output
)
assert result.exit_code == FAILURE_EXIT_STATUS
# test that error don't occur when issuer balance > 0
else:
tx.transaction_confirmation.assert_called_once()