Skip to content
Snippets Groups Projects
Commit 676b1099 authored by Vincent Texier's avatar Vincent Texier
Browse files

Merge branch 'transaction' into 'dev'

Several transaction enhancements, other improvements

See merge request !56
parents 3a1e5d61 4db793ba
Branches
Tags
1 merge request!56Several transaction enhancements, other improvements
Pipeline #5330 passed
......@@ -37,8 +37,21 @@ push_to_github:
- eval "$(pyenv init -)"
- pyenv shell $PYENV_PYTHON_VERSION
.changes: &changes
except:
changes:
- CHANGELOG.md
- ci/*
- config
- docs
- LICENSE*
- Makefile
- README*
- release.sh
build: &build
<<: *pyenv
<<: *changes
stage: build
script:
- pip install -r requirements.txt
......@@ -47,6 +60,7 @@ build: &build
test:
<<: *pyenv
<<: *changes
stage: test
script:
- pip install coveralls
......@@ -55,6 +69,7 @@ test:
mypy:
<<: *pyenv
<<: *changes
stage: test
script:
- pip install -r requirements_dev.txt
......
## v0.54.0 (XX April 2019)
### Code/tests
- Fix OutputSource and InputSource from_inline() regex matching
- Transaction document: tests and code: drop versions 2 and 3 management
- Block document: code: drop vensions 2 and 3 management
- Block document: Upgrade blocks to v11 and TX to v10
- Add OutputSource.inline_condition() method
### Other
- CI: Do not trigger build, tests, type check on modification of non-relevant files
- Makefile: use python3 module to run tests and type check
- Add coveralls as dev dependency
- setup.py: add classifiers: Python versions, Intended Audience
- Add CHANGELOG.md from v0.53.1
- Thanks @Moul, @vtexier
## v0.53.1 (18 April 2019)
- Implement equality `__eq__()` and `__hash__()` methods for InputSource and OutputSource classes
Thanks @Moul, @vtexier
## v0.53.0 (30 March 2019)
- To be completed…
......@@ -6,8 +6,8 @@ docs:
# run tests
tests:
python -m unittest ${test_filter}
python3 -m unittest ${TESTS_FILTER}
# check static typing
check:
mypy duniterpy --ignore-missing-imports
python3 -m mypy duniterpy --ignore-missing-imports
......@@ -69,9 +69,9 @@ Development
make tests
* Run only some unit tests with::
* Run only some unit tests by passing a special ENV variable::
make tests test_filter=tests.documents.test_block.TestBlock.test_fromraw
make tests TESTS_FILTER=tests.documents.test_block.TestBlock.test_fromraw
Documentation
-------------
......
......@@ -75,8 +75,6 @@ The class Block handles Block documents.
re_previoushash = re.compile("PreviousHash: ({block_hash_regex})\n".format(block_hash_regex=BLOCK_HASH_REGEX))
re_previousissuer = re.compile("PreviousIssuer: ({pubkey_regex})\n".format(pubkey_regex=PUBKEY_REGEX))
re_parameters = re.compile("Parameters: ([0-9]+\\.[0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):\
([0-9]+):([0-9]+):([0-9]+\\.[0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+\\.[0-9]+)\n")
re_parameters_v10 = re.compile("Parameters: ([0-9]+\\.[0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):\
([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+\\.[0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+):([0-9]+\\.[0-9]+):\
([0-9]+):([0-9]+):([0-9]+)\n")
re_memberscount = re.compile("MembersCount: ([0-9]+)\n")
......@@ -252,24 +250,18 @@ The class Block handles Block documents.
ud = int(Block.parse_field("UD", lines[n]))
n += 1
if version >= 3 or ud:
unit_base = int(Block.parse_field("UnitBase", lines[n]))
n += 1
issuer = Block.parse_field("Issuer", lines[n])
n += 1
if version >= 3:
issuers_frame = Block.parse_field("IssuersFrame", lines[n])
n += 1
issuers_frame_var = Block.parse_field("IssuersFrameVar", lines[n])
n += 1
different_issuers_count = Block.parse_field("DifferentIssuersCount", lines[n])
n += 1
else:
issuers_frame = None
issuers_frame_var = None
different_issuers_count = None
prev_hash = None
prev_issuer = None
......@@ -283,12 +275,6 @@ The class Block handles Block documents.
parameters = None
if number == 0:
try:
if version >= 10:
params_match = Block.re_parameters_v10.match(lines[n])
if params_match is None:
raise MalformedDocumentError("Parameters")
parameters = params_match.groups()
else:
params_match = Block.re_parameters.match(lines[n])
if params_match is None:
raise MalformedDocumentError("Parameters")
......@@ -374,12 +360,7 @@ The class Block handles Block documents.
unlocks_num = int(header_data.group(4))
outputs_num = int(header_data.group(5))
has_comment = int(header_data.group(6))
if version > 2:
if tx_version <= 2:
raise MalformedDocumentError("TX document is using wrong version")
sup_lines = 2
else:
sup_lines = 1
tx_max = n + sup_lines + issuers_num * 2 + inputs_num + unlocks_num + outputs_num + has_comment
for i in range(n, tx_max):
tx_lines += lines[n]
......@@ -419,12 +400,10 @@ MedianTime: {mediantime}
if self.ud:
doc += "UniversalDividend: {0}\n".format(self.ud)
if self.version >= 3 or self.ud:
doc += "UnitBase: {0}\n".format(self.unit_base)
doc += "Issuer: {0}\n".format(self.issuer)
if self.version >= 3:
doc += """IssuersFrame: {0}
IssuersFrameVar: {1}
DifferentIssuersCount: {2}
......
......@@ -56,22 +56,22 @@ class BlockUID:
def __lt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return NotImplemented
return self.number < other.number
def __gt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return NotImplemented
return self.number > other.number
def __le__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return NotImplemented
return self.number <= other.number
def __ge__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return NotImplemented
return self.number >= other.number
def __hash__(self) -> int:
......
......@@ -44,8 +44,6 @@ class Document:
:param currency: Name of the currency
:param signatures: List of signatures
"""
if version < 2:
raise MalformedDocumentError("Version 1 documents are not handled by duniterpy>0.2")
self.version = version
self.currency = currency
if signatures:
......
......@@ -50,13 +50,8 @@ class InputSource:
"""
re_inline = re.compile(
"(?:(?:(D):({pubkey_regex}):({block_id_regex}))|(?:(T):({transaction_hash_regex}):([0-9]+)))\n"
.format(pubkey_regex=PUBKEY_REGEX,
block_id_regex=BLOCK_ID_REGEX,
transaction_hash_regex=TRANSACTION_HASH_REGEX))
re_inline_v3 = re.compile(
"([0-9]+):([0-9]+):(?:(?:(D):({pubkey_regex}):({block_id_regex}))|(?:(T):({transaction_hash_regex}):\
([0-9]+)))\n"
"([0-9]+):([0-9]):(?:(?:(D):({pubkey_regex}):({block_id_regex}))|(?:(T):({transaction_hash_regex}):\
([0-9]+)))"
.format(pubkey_regex=PUBKEY_REGEX,
block_id_regex=BLOCK_ID_REGEX,
transaction_hash_regex=TRANSACTION_HASH_REGEX))
......@@ -94,23 +89,14 @@ class InputSource:
return hash((self.amount, self.base, self.source, self.origin_id, self.index))
@classmethod
def from_inline(cls: Type[InputSourceType], tx_version: int, inline: str) -> InputSourceType:
def from_inline(cls: Type[InputSourceType], inline: str) -> InputSourceType:
"""
Return Transaction instance from inline string format
:param tx_version: Version number of the document
:param inline: Inline string format
:return:
"""
if tx_version == 2:
data = InputSource.re_inline.match(inline)
if data is None:
raise MalformedDocumentError("Inline input")
source_offset = 0
amount = 0
base = 0
else:
data = InputSource.re_inline_v3.match(inline)
if data is None:
raise MalformedDocumentError("Inline input")
source_offset = 2
......@@ -127,18 +113,12 @@ class InputSource:
return cls(amount, base, source, origin_id, index)
def inline(self, tx_version: int) -> str:
def inline(self) -> str:
"""
Return an inline string format of the document
:param tx_version: Version number of the document
:return:
"""
if tx_version == 2:
return "{0}:{1}:{2}".format(self.source,
self.origin_id,
self.index)
else:
return "{0}:{1}:{2}:{3}:{4}".format(self.amount,
self.base,
self.source,
......@@ -154,7 +134,7 @@ class OutputSource:
"""
A Transaction OUTPUT
"""
re_inline = re.compile("([0-9]+):([0-9]+):(.*)\n")
re_inline = re.compile("([0-9]+):([0-9]):(.*)")
def __init__(self, amount: int, base: int, condition: str) -> None:
"""
......@@ -200,13 +180,21 @@ class OutputSource:
def inline(self) -> str:
"""
Return an inline string format of the document
Return an inline string format of the output source
:return:
"""
return "{0}:{1}:{2}".format(self.amount, self.base,
pypeg2.compose(self.condition, output.Condition))
def inline_condition(self) -> str:
"""
Return an inline string format of the output source’s condition
:return:
"""
return pypeg2.compose(self.condition, output.Condition)
@staticmethod
def condition_from_text(text) -> Condition:
"""
......@@ -557,8 +545,6 @@ Comment: {comment}
locktime = int(header_data.group(7))
n += 1
blockstamp = None # type: Optional[BlockUID]
if version >= 3:
blockstamp = BlockUID.from_str(Transaction.parse_field("CompactBlockstamp", lines[n]))
n += 1
......@@ -573,7 +559,7 @@ Comment: {comment}
n += 1
for i in range(0, inputs_num):
input_source = InputSource.from_inline(version, lines[n])
input_source = InputSource.from_inline(lines[n])
inputs.append(input_source)
n += 1
......@@ -651,7 +637,7 @@ Comment: {comment}
if Transaction.re_inputs.match(lines[n]):
n += 1
while Transaction.re_unlocks.match(lines[n]) is None:
input_source = InputSource.from_inline(version, lines[n])
input_source = InputSource.from_inline(lines[n])
inputs.append(input_source)
n += 1
......@@ -704,7 +690,7 @@ Currency: {1}
doc += "Inputs:\n"
for i in self.inputs:
doc += "{0}\n".format(i.inline(self.version))
doc += "{0}\n".format(i.inline())
doc += "Unlocks:\n"
for u in self.unlocks:
......@@ -747,7 +733,7 @@ COMMENT
for pubkey in self.issuers:
doc += "{0}\n".format(pubkey)
for i in self.inputs:
doc += "{0}\n".format(i.inline(self.version))
doc += "{0}\n".format(i.inline())
for u in self.unlocks:
doc += "{0}\n".format(u.inline())
for o in self.outputs:
......
coveralls
mypy
sphinx
sphinx_rtd_theme
......@@ -63,13 +63,16 @@ setup(
test_suite="tests",
classifiers=[
"Programming Language :: Python",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.5",
"Topic :: Software Development :: Libraries",
"Intended Audience :: Developers",
],
install_requires=install_requires,
dependency_links=dependency_links
......
......@@ -8,14 +8,18 @@ import unittest
from duniterpy.documents.block import Block
from duniterpy.documents.block_uid import BlockUID, block_uid
raw_block = """Version: 2
raw_block = """Version: 11
Type: Block
Currency: zeta_brouzouf
Number: 15
PoWMin: 4
Time: 1418083330
MedianTime: 1418080208
UnitBase: 0
Issuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
IssuersFrame: 1
IssuersFrameVar: 0
DifferentIssuersCount: 0
PreviousHash: 0000E73C340601ACA1AD5AAA5B5E56B03E178EF8
PreviousIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
MembersCount: 4
......@@ -32,14 +36,18 @@ Nonce: 45079
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
"""
raw_block_with_tx = """Version: 2
raw_block_with_tx = """Version: 11
Type: Block
Currency: meta_brouzouf
Number: 34436
PoWMin: 5
Time: 1443896211
MedianTime: 1443881811
UnitBase: 0
Issuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
IssuersFrame: 1
IssuersFrameVar: 0
DifferentIssuersCount: 0
PreviousHash: 000002B06C990DEBD5C1D947289C2CF4F4396FB2
PreviousIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
MembersCount: 19
......@@ -54,26 +62,28 @@ Certifications:
5ocqzyDMMWf1V8bsoNhWb1iNwax1e9M7VTUN6navs8of:ATkjQPa4sn4LBF69jqEPzFtRdHYJs6MJQjvP8JdN7MtN:0:6TuxRcARnpo13l3cXtgPTkjJlv8DZOUvsAzmZJMbjHZbbZfDQ6MJpH9DIuH0eyG3WGc0EX/046mbMGBrKKg9DQ==
ATkjQPa4sn4LBF69jqEPzFtRdHYJs6MJQjvP8JdN7MtN:2qwGeLWoPG7db72bKXPfJpAtj67FYDnPaJn2JB7tyXxJ:0:LusTbb7CgwrqqacDKjtldw60swwvDBH8wVUIJN4SWRb2pZPJSpDxgqaGyjC5P9i/DendfyQWc7cfzPDqSZmZAg==
Transactions:
TX:2:1:3:3:1:0:0
TX:10:1:3:3:1:0:0
33363-000021C4B5BE2DA996F953DC09482F4FA2FA68774B1A38FAB03B2AAB4A08EBE0
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:0
T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:10
D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:88
5200:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:0
500:0:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:10
20:0:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:88
0:SIG(0)
1:SIG(0)
2:SIG(0)
30:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
TX:2:3:6:6:3:1:0
TX:10:3:6:6:3:1:0
33363-000021C4B5BE2DA996F953DC09482F4FA2FA68774B1A38FAB03B2AAB4A08EBE0
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
78900:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
700:0:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
8900:0:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
780:0:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
780:0:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
8900:0:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
0:SIG(0)
1:XHX(7665798292)
2:SIG(0)
......@@ -92,7 +102,7 @@ Nonce: 581
nY/MsFU2luiohLmSiOOimL1RIqbriOBgc22ua03Z2dhxtSJxKZeGNGDvl1jaXgmEBRnXU87yXbZ7ioOS/AAVCA==
"""
raw_block_zero = """Version: 10
raw_block_zero = """Version: 11
Type: Block
Currency: zeta_brouzouf
Number: 0
......@@ -139,14 +149,18 @@ Nonce: 2125
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
"""
raw_block_with_leavers = """Version: 2
raw_block_with_leavers = """Version: 11
Type: Block
Currency: meta_brouzouf
Number: 34895
PoWMin: 4
Time: 1444434128
MedianTime: 1444426438
UnitBase: 0
Issuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
IssuersFrame: 1
IssuersFrameVar: 0
DifferentIssuersCount: 0
PreviousHash: 0000E88115ADDF79344372C0212928501E21622B
PreviousIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk
MembersCount: 21
......@@ -164,7 +178,7 @@ Nonce: 9906
5LZCFSnm5FkFihPBTpmsPyILEdvu8MXfJOp6OR4d1s+/e2jVWg4J6YSDfO2KBBPgubASyr2QwQuiBlYD2918Bw==
"""
raw_block_with_excluded = """Version: 3
raw_block_with_excluded = """Version: 11
Type: Block
Currency: test_net
Number: 33365
......@@ -189,7 +203,7 @@ Excluded:
2VAxjr8QoJtSzhE7APno4AkR2RAQNySpNNvDzMgPotSF
Certifications:
Transactions:
TX:3:1:4:4:12:1:0
TX:10:1:4:4:12:1:0
33363-000021C4B5BE2DA996F953DC09482F4FA2FA68774B1A38FAB03B2AAB4A08EBE0
TENGx7WtzFsTXwnbrPEvb6odX2WnqYcnnrjiiLvp1mS
5:0:T:D25272F1D778B52798B7A51CF0CE21F7C5812F841374508F4367872D4A47F0F7:0
......@@ -219,7 +233,7 @@ Nonce: 137387
GmgYhWrwCtsK7t2B/omPpxZ8EfJgv9UYzJIFo++Za+A0Mo70xRfZG7kywxbQTTxDk/V7r90P946N89vdVjv1Bg==
"""
negative_issuers_frame_var = """Version: 3
negative_issuers_frame_var = """Version: 11
Type: Block
Currency: test_net
Number: 34662
......@@ -242,7 +256,7 @@ Revoked:
Excluded:
Certifications:
Transactions:
TX:3:1:4:4:2:1:0
TX:10:1:4:4:2:1:0
34660-00001EEB3FDCEB2F9F39F931ED8F6D419C4C64B4D3F7EA52C35FB6B07A085664
5ocqzyDMMWf1V8bsoNhWb1iNwax1e9M7VTUN6navs8of
765201:3:T:636150D38D565DA0B9717E93C2AD8D6270FA032BF963360ECFCDD55F44493F08:1
......@@ -266,7 +280,7 @@ WnJvw204wccmSBQK9UE2rCFw0EG34zf+b58n2KTLwSIhTpgmGsnr5ohkSyYZYcLEKjisLXKNCmMl7D1Q
class TestBlock(unittest.TestCase):
def test_fromraw(self):
block = Block.from_signed_raw(raw_block)
self.assertEqual(block.version, 2)
self.assertEqual(block.version, 11)
self.assertEqual(block.currency, "zeta_brouzouf")
self.assertEqual(block.noonce, 45079)
self.assertEqual(block.number, 15)
......@@ -287,7 +301,7 @@ class TestBlock(unittest.TestCase):
def test_from_signed_raw_block_zero(self):
block = Block.from_signed_raw(raw_block_zero)
self.assertEqual(block.version, 10)
self.assertEqual(block.version, 11)
self.assertEqual(block.currency, "zeta_brouzouf")
self.assertEqual(block.noonce, 2125)
self.assertEqual(block.number, 0)
......@@ -315,7 +329,7 @@ class TestBlock(unittest.TestCase):
rendered_raw = block.signed_raw()
from_rendered_raw = Block.from_signed_raw(rendered_raw)
self.assertEqual(from_rendered_raw.version, 2)
self.assertEqual(from_rendered_raw.version, 11)
self.assertEqual(from_rendered_raw.currency, "zeta_brouzouf")
self.assertEqual(from_rendered_raw.noonce, 45079)
self.assertEqual(from_rendered_raw.number, 15)
......@@ -341,7 +355,7 @@ class TestBlock(unittest.TestCase):
rendered_raw = block.signed_raw()
from_rendered_raw = block.from_signed_raw(rendered_raw)
self.assertEqual(from_rendered_raw.version, 10)
self.assertEqual(from_rendered_raw.version, 11)
self.assertEqual(from_rendered_raw.currency, "zeta_brouzouf")
self.assertEqual(from_rendered_raw.noonce, 2125)
self.assertEqual(from_rendered_raw.number, 0)
......@@ -365,7 +379,7 @@ class TestBlock(unittest.TestCase):
rendered_raw = block.signed_raw()
from_rendered_raw = block.from_signed_raw(rendered_raw)
self.assertEqual(from_rendered_raw.version, 2)
self.assertEqual(from_rendered_raw.version, 11)
self.assertEqual(from_rendered_raw.currency, "meta_brouzouf")
self.assertEqual(from_rendered_raw.noonce, 581)
self.assertEqual(from_rendered_raw.number, 34436)
......@@ -389,7 +403,7 @@ class TestBlock(unittest.TestCase):
block = Block.from_signed_raw(raw_block_with_leavers)
rendered_raw = block.signed_raw()
from_rendered_raw = block.from_signed_raw(rendered_raw)
self.assertEqual(from_rendered_raw.version, 2)
self.assertEqual(from_rendered_raw.version, 11)
self.assertEqual(from_rendered_raw.currency, "meta_brouzouf")
self.assertEqual(from_rendered_raw.noonce, 9906)
self.assertEqual(from_rendered_raw.number, 34895)
......@@ -452,7 +466,7 @@ class TestBlock(unittest.TestCase):
self.fail("Empty blockuid __nonzero__ comparison failed")
def test_proof_of_work(self):
block = """Version: 5
block = """Version: 11
Type: Block
Currency: test_net
Number: 60803
......
......@@ -6,7 +6,7 @@ Created on 12 déc. 2014
import unittest
import pypeg2
from duniterpy.grammars import output
from duniterpy.documents.transaction import Transaction, reduce_base, SimpleTransaction
from duniterpy.documents.transaction import Transaction, reduce_base, SimpleTransaction, InputSource, OutputSource
compact_change = """TX:10:1:1:1:1:1:0
13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
......@@ -35,16 +35,17 @@ Comment: XHX for pubkey DCYELkvV1aAsxFv58SbfRerHy5giJwKA1i4ZKTTcVGZe
GXGephqTSJfb+8xsG/UMKRW0y+edL4RoMHM+OlgFq1aYOuaQ3/CtBKVSA01n2mkI7zwepeIABSjS94iVH4vZDg==
"""
tx_compact = """TX:2:3:6:6:3:1:0
tx_compact = """TX:10:3:6:6:3:1:0
13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
230:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
2230:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
2430:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
2310:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
30:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
2330:2:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
0:SIG(0)
1:XHX(7665798292)
2:SIG(0)
......@@ -60,48 +61,17 @@ D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk
"""
tx_compact_2 = """TX:2:1:1:1:2:0:0
simple_tx_compact = """TX:10:1:1:1:2:0:0
13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92
D:GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92:471
100:0:D:GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92:471
0:SIG(0)
90:0:SIG(5zDvFjJB1PGDQNiExpfzL9c1tQGs6xPA8mf1phr3VoVi)
10:0:SIG(GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92)
XDQeEMcJDd+XVGaFIZc8d4kKRJgsPuWAPVNG5UKNk8mDZx2oE1kTP/hbxiFx6yDouBELCswuf/X6POK9ES7JCA==
"""
tx_raw = """Version: 2
Type: Transaction
Currency: beta_brousouf
Locktime: 0
Issuers:
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
Inputs:
T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
Unlocks:
0:SIG(0)
1:XHX(7665798292)
2:SIG(0)
3:SIG(0) SIG(2)
4:SIG(0) SIG(1) SIG(2)
5:SIG(2)
Outputs:
120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))
Comment: -----@@@----- (why not this comment?)
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk
"""
tx_raw_v3 = """Version: 3
tx_raw = """Version: 10
Type: Transaction
Currency: beta_brousouf
Blockstamp: 32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD
......@@ -138,109 +108,8 @@ Comment: -----@@@----- (why not this comment?)
class TestTransaction(unittest.TestCase):
def test_fromcompact(self):
tx = Transaction.from_compact("zeta_brousouf", tx_compact)
self.assertEqual(tx.version, 2)
self.assertEqual(tx.currency, "zeta_brousouf")
self.assertEqual(len(tx.issuers), 3)
self.assertEqual(len(tx.inputs), 6)
self.assertEqual(len(tx.unlocks), 6)
self.assertEqual(len(tx.outputs), 3)
self.assertEqual(tx.issuers[0], "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(tx.issuers[1], "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp")
self.assertEqual(tx.issuers[2], "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[0].source, 'T')
self.assertEqual(tx.inputs[0].origin_id, "6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3")
self.assertEqual(tx.inputs[0].index, 2)
self.assertEqual(tx.inputs[1].source, 'T')
self.assertEqual(tx.inputs[1].origin_id, "3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435")
self.assertEqual(tx.inputs[1].index, 8)
self.assertEqual(tx.inputs[2].source, 'D')
self.assertEqual(tx.inputs[2].origin_id, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(tx.inputs[2].index, 46)
self.assertEqual(tx.inputs[3].source, 'T')
self.assertEqual(tx.inputs[3].origin_id, "A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956")
self.assertEqual(tx.inputs[3].index, 3)
self.assertEqual(tx.inputs[4].source, 'T')
self.assertEqual(tx.inputs[4].origin_id, "67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B")
self.assertEqual(tx.inputs[4].index, 5)
self.assertEqual(tx.inputs[5].source, 'D')
self.assertEqual(tx.inputs[5].origin_id, "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[5].index, 46)
self.assertEqual(tx.unlocks[0].index, 0)
self.assertEqual(str(tx.unlocks[0].parameters[0]), "SIG(0)")
self.assertEqual(tx.unlocks[1].index, 1)
self.assertEqual(str(tx.unlocks[1].parameters[0]), "XHX(7665798292)")
self.assertEqual(tx.unlocks[2].index, 2)
self.assertEqual(str(tx.unlocks[2].parameters[0]), "SIG(0)")
self.assertEqual(tx.unlocks[3].index, 3)
self.assertEqual(str(tx.unlocks[3].parameters[0]), "SIG(0)")
self.assertEqual(str(tx.unlocks[3].parameters[1]), "SIG(2)")
self.assertEqual(tx.unlocks[4].index, 4)
self.assertEqual(str(tx.unlocks[4].parameters[0]), "SIG(0)")
self.assertEqual(str(tx.unlocks[4].parameters[1]), "SIG(1)")
self.assertEqual(str(tx.unlocks[4].parameters[2]), "SIG(2)")
self.assertEqual(tx.unlocks[5].index, 5)
self.assertEqual(str(tx.unlocks[5].parameters[0]), "SIG(2)")
self.assertEqual(tx.outputs[0].amount, 120)
self.assertEqual(tx.outputs[0].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[0].condition, output.Condition),
"SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)")
self.assertEqual(tx.outputs[1].amount, 146)
self.assertEqual(tx.outputs[1].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[1].condition, output.Condition),
"SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)")
self.assertEqual(tx.outputs[2].amount, 49)
self.assertEqual(tx.outputs[2].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[2].condition, output.Condition),
"(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))")
self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)")
self.assertEqual(tx.signatures[0],
"42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r")
self.assertEqual(tx.signatures[1],
"2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX")
self.assertEqual(tx.signatures[2],
"2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk")
def test_fromcompact2(self):
tx = Transaction.from_compact("zeta_brousouf", tx_compact_2)
self.assertEqual(tx.version, 2)
self.assertEqual(tx.version, 10)
self.assertEqual(tx.currency, "zeta_brousouf")
self.assertEqual(len(tx.issuers), 1)
self.assertEqual(len(tx.inputs), 1)
self.assertEqual(len(tx.unlocks), 1)
self.assertEqual(len(tx.outputs), 2)
self.assertEqual(tx.issuers[0], "GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92")
self.assertEqual(tx.inputs[0].source, 'D')
self.assertEqual(tx.inputs[0].origin_id, "GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92")
self.assertEqual(tx.inputs[0].index, 471)
self.assertEqual(tx.unlocks[0].index, 0)
self.assertEqual(str(tx.unlocks[0].parameters[0]), "SIG(0)")
self.assertEqual(tx.outputs[0].amount, 90)
self.assertEqual(tx.outputs[0].base, 0)
self.assertEqual(pypeg2.compose(tx.outputs[0].condition, output.Condition),
"SIG(5zDvFjJB1PGDQNiExpfzL9c1tQGs6xPA8mf1phr3VoVi)")
self.assertEqual(type(tx.outputs[0].condition.left), output.SIG)
self.assertEqual(tx.outputs[1].amount, 10)
self.assertEqual(tx.outputs[1].base, 0)
self.assertEqual(pypeg2.compose(tx.outputs[1].condition, output.Condition),
"SIG(GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92)")
self.assertEqual(type(tx.outputs[1].condition.left), output.SIG)
self.assertEqual(tx.signatures[0],
"XDQeEMcJDd+XVGaFIZc8d4kKRJgsPuWAPVNG5UKNk8mDZx2oE1kTP/hbxiFx6yDouBELCswuf/X6POK9ES7JCA==")
def test_fromraw(self):
tx = Transaction.from_signed_raw(tx_raw)
self.assertEqual(tx.version, 2)
self.assertEqual(tx.currency, "beta_brousouf")
self.assertEqual(len(tx.issuers), 3)
self.assertEqual(len(tx.inputs), 6)
self.assertEqual(len(tx.unlocks), 6)
......@@ -250,21 +119,33 @@ class TestTransaction(unittest.TestCase):
self.assertEqual(tx.issuers[1], "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp")
self.assertEqual(tx.issuers[2], "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[0].amount, 230)
self.assertEqual(tx.inputs[0].base, 2)
self.assertEqual(tx.inputs[0].source, 'T')
self.assertEqual(tx.inputs[0].origin_id, "6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3")
self.assertEqual(tx.inputs[0].index, 2)
self.assertEqual(tx.inputs[1].amount, 2230)
self.assertEqual(tx.inputs[1].base, 2)
self.assertEqual(tx.inputs[1].source, 'T')
self.assertEqual(tx.inputs[1].origin_id, "3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435")
self.assertEqual(tx.inputs[1].index, 8)
self.assertEqual(tx.inputs[2].amount, 2430)
self.assertEqual(tx.inputs[2].base, 2)
self.assertEqual(tx.inputs[2].source, 'D')
self.assertEqual(tx.inputs[2].origin_id, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(tx.inputs[2].index, 46)
self.assertEqual(tx.inputs[3].amount, 2310)
self.assertEqual(tx.inputs[3].base, 2)
self.assertEqual(tx.inputs[3].source, 'T')
self.assertEqual(tx.inputs[3].origin_id, "A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956")
self.assertEqual(tx.inputs[3].index, 3)
self.assertEqual(tx.inputs[4].amount, 30)
self.assertEqual(tx.inputs[4].base, 2)
self.assertEqual(tx.inputs[4].source, 'T')
self.assertEqual(tx.inputs[4].origin_id, "67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B")
self.assertEqual(tx.inputs[4].index, 5)
self.assertEqual(tx.inputs[5].amount, 2330)
self.assertEqual(tx.inputs[5].base, 2)
self.assertEqual(tx.inputs[5].source, 'D')
self.assertEqual(tx.inputs[5].origin_id, "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[5].index, 46)
......@@ -312,80 +193,7 @@ class TestTransaction(unittest.TestCase):
rendered_tx = tx.signed_raw()
from_rendered_tx = Transaction.from_signed_raw(rendered_tx)
self.assertEqual(tx.version, 2)
self.assertEqual(tx.currency, "beta_brousouf")
self.assertEqual(len(tx.issuers), 3)
self.assertEqual(len(tx.inputs), 6)
self.assertEqual(len(tx.unlocks), 6)
self.assertEqual(len(tx.outputs), 3)
self.assertEqual(tx.issuers[0], "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(tx.issuers[1], "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp")
self.assertEqual(tx.issuers[2], "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[0].source, 'T')
self.assertEqual(tx.inputs[0].origin_id, "6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3")
self.assertEqual(tx.inputs[0].index, 2)
self.assertEqual(tx.inputs[1].source, 'T')
self.assertEqual(tx.inputs[1].origin_id, "3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435")
self.assertEqual(tx.inputs[1].index, 8)
self.assertEqual(tx.inputs[2].source, 'D')
self.assertEqual(tx.inputs[2].origin_id, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY")
self.assertEqual(tx.inputs[2].index, 46)
self.assertEqual(tx.inputs[3].source, 'T')
self.assertEqual(tx.inputs[3].origin_id, "A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956")
self.assertEqual(tx.inputs[3].index, 3)
self.assertEqual(tx.inputs[4].source, 'T')
self.assertEqual(tx.inputs[4].origin_id, "67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B")
self.assertEqual(tx.inputs[4].index, 5)
self.assertEqual(tx.inputs[5].source, 'D')
self.assertEqual(tx.inputs[5].origin_id, "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB")
self.assertEqual(tx.inputs[5].index, 46)
self.assertEqual(tx.unlocks[0].index, 0)
self.assertEqual(str(tx.unlocks[0].parameters[0]), "SIG(0)")
self.assertEqual(tx.unlocks[1].index, 1)
self.assertEqual(str(tx.unlocks[1].parameters[0]), "XHX(7665798292)")
self.assertEqual(tx.unlocks[2].index, 2)
self.assertEqual(str(tx.unlocks[2].parameters[0]), "SIG(0)")
self.assertEqual(tx.unlocks[3].index, 3)
self.assertEqual(str(tx.unlocks[3].parameters[0]), "SIG(0)")
self.assertEqual(str(tx.unlocks[3].parameters[1]), "SIG(2)")
self.assertEqual(tx.unlocks[4].index, 4)
self.assertEqual(str(tx.unlocks[4].parameters[0]), "SIG(0)")
self.assertEqual(str(tx.unlocks[4].parameters[1]), "SIG(1)")
self.assertEqual(str(tx.unlocks[4].parameters[2]), "SIG(2)")
self.assertEqual(tx.unlocks[5].index, 5)
self.assertEqual(str(tx.unlocks[5].parameters[0]), "SIG(2)")
self.assertEqual(tx.outputs[0].amount, 120)
self.assertEqual(tx.outputs[0].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[0].condition, output.Condition),
"SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)")
self.assertEqual(tx.outputs[1].amount, 146)
self.assertEqual(tx.outputs[1].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[1].condition, output.Condition),
"SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)")
self.assertEqual(tx.outputs[2].amount, 49)
self.assertEqual(tx.outputs[2].base, 2)
self.assertEqual(pypeg2.compose(tx.outputs[2].condition, output.Condition),
"(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))")
self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)")
self.assertEqual(tx.signatures[0],
"42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r")
self.assertEqual(tx.signatures[1],
"2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX")
self.assertEqual(tx.signatures[2],
"2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk")
def test_fromraw_toraw_v3(self):
tx = Transaction.from_signed_raw(tx_raw_v3)
rendered_tx = tx.signed_raw()
from_rendered_tx = Transaction.from_signed_raw(rendered_tx)
self.assertEqual(tx.version, 3)
self.assertEqual(tx.version, 10)
self.assertEqual(tx.currency, "beta_brousouf")
self.assertEqual(tx.blockstamp.number, 32)
self.assertEqual(tx.blockstamp.sha_hash, "DB30D958EE5CB75186972286ED3F4686B8A1C2CD")
......@@ -475,8 +283,26 @@ class TestTransaction(unittest.TestCase):
self.assertEqual(computed[1], 5)
def test_is_simple(self):
tx = Transaction.from_compact("zeta_brousouf", tx_compact_2)
tx = Transaction.from_compact("zeta_brousouf", simple_tx_compact)
self.assertTrue(SimpleTransaction.is_simple(tx))
tx = Transaction.from_compact("zeta_brousouf", tx_compact)
self.assertFalse(SimpleTransaction.is_simple(tx))
def test_inputsource_from_inline(self):
input_source_str = "30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2"
i = InputSource.from_inline(input_source_str)
self.assertEqual(i.inline(), input_source_str)
def test_outputsource_from_inline(self):
output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"
o = OutputSource.from_inline(output_source_str)
self.assertEqual(o.inline(), output_source_str)
def test_outputsource_inline_condition(self):
output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"
o = OutputSource.from_inline(output_source_str)
self.assertEqual(o.inline_condition(), output_source_str.split(":")[2])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment