diff --git a/.gitignore b/.gitignore
index b582e25..a4faf77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,3 +112,5 @@ venv.bak/
.mypy_cache/
.dmypy.json
dmypy.json
+
+.vscode/
diff --git a/README.md b/README.md
index 66f7668..8efae95 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
-# scrmbl
+# scrmbl
-🕵️ Library for "scrambled" printing in terminal
+Library and CLI for "scrambled" printing in terminal.
+
+Have you ever wanted your text to look like some corny action movie?
![demo gif](https://raw.githubusercontent.com/etienne-napoleone/scrmbl/develop/demo.gif)
@@ -10,6 +12,14 @@
## Install
+### CLI
+
+```
+pip3 install --user scrmbl
+```
+
+### Library
+
Using pip in a virtualenv.
```bash
@@ -22,7 +32,7 @@ Using Poetry:
poetry add scrmbl
```
-Using pipenv:
+Using Pipenv:
```bash
pipenv install scrmbl
@@ -30,33 +40,52 @@ pipenv install scrmbl
## Usage
+Refer to the gif to see the effect
+
+### CLI
+
+```
+Usage: scrmbl [OPTIONS] [MESSAGE]
+
+ Scrmbl print the given message.
+
+Options:
+ -s, --speed FLOAT Time in seconds between prints. Default: 0.05
+ -i, --iterations INTEGER Number of iterations per character. Default: 2
+ -c, --charset FILE Set of chars to scramble.
+ --version Show the version and exit.
+ --help Show this message and exit.
+```
+
+Can also read from stdin.
+
+```bash
+ls -lrtha | scrmbl
+```
+
+## Library
+
```python
>>> import scrmbl
-# refer to the gif to see the effect
>>> scrmbl.echo('09:30pm, Washington, NSA HEADQUARTERS')
'09:30pm, Washington, NSA HEADQUARTERS'
# handle multiline
>>> scrmbl.echo('09:30pm, Washington\nNSA HEADQUARTERS')
-'09:30pm, Washington'
-'NSA HEADQUARTERS'
+'02:56am, New-York'
+'FBI HEADQUARTERS'
# custom settings:
-# charset = List of characters to randomly iterate through
-# speed = Milliseconds to wait between each iteration
+# charset = String of characters to scramble with
+# speed = Time in seconds between prints
# iterations = number of iterations before printing the final character
->>> scrmbl.echo('NSA OFFICE', charset=['N', 'S', 'A'], speed=0.2, iterations=6)
-'NSA OFFICE'
-
-# premade charsets:
-# LETTERS_LOWER
-# LETTERS_UPPER
-# FIGURES
-# SPECIALS
-# LETTERS (LETTERS_LOWER + LETTERS_UPPER)
-# ALPHANUMERICS (LETTERS + FIGURES)
-# ALL (ALPHANUMERICS + SPECIALS)
->>> scrmbl.echo('NSA OFFICE', charset=scrmbl.charsets.LETTERS)
-'NSA OFFICE'
+>>> scrmbl.echo('NSA OFFICE', charset='ABCDefg/-', speed=0.2, iterations=6)
+'CIA OFFICE'
```
+
+## Thanks
+
+Special thanks for contributing:
+- [@podstava](https://github.com/podstava)
+- [@0jdxt](https://github.com/0jdxt)
diff --git a/pyproject.lock b/pyproject.lock
index fe4ccc2..2a36e45 100644
--- a/pyproject.lock
+++ b/pyproject.lock
@@ -34,6 +34,15 @@ platform = "*"
python-versions = "*"
version = "3.0.4"
+[[package]]
+category = "main"
+description = "Composable command line interface toolkit"
+name = "click"
+optional = false
+platform = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+version = "7.0"
+
[[package]]
category = "dev"
description = "Cross-platform colored terminal text."
@@ -199,6 +208,19 @@ version = "*"
python = "<3.6"
version = ">=2.2.0"
+[[package]]
+category = "dev"
+description = "Pytest plugin for measuring coverage."
+name = "pytest-cov"
+optional = false
+platform = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+version = "2.6.0"
+
+[package.dependencies]
+coverage = ">=4.4"
+pytest = ">=2.9"
+
[[package]]
category = "dev"
description = "Python HTTP for Humans."
@@ -233,7 +255,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4"
version = "1.23"
[metadata]
-content-hash = "c303f82a4563ff6309ba7d284166637717d51244572081295714e81d6bda02d1"
+content-hash = "b8e8bd0c8b465ec69f789637c436c083c1ecd8934a7ac5a7fa24e7a2ecd9e09b"
platform = "*"
python-versions = "^3.5"
@@ -242,6 +264,7 @@ atomicwrites = ["0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c
attrs = ["10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", "ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"]
certifi = ["376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", "456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a"]
chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"]
+click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"]
colorama = ["463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", "48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"]
coverage = ["03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", "0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", "104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a", "10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", "15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd", "198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", "1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2", "23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", "28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", "2a5b73210bad5279ddb558d9a2bfedc7f4bf6ad7f3c988641d83c40293deaec1", "2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", "337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", "3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", "3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", "3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", "3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", "4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", "56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", "5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", "69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", "6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", "701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", "7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", "76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", "7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", "7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", "7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", "8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", "9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", "9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4", "ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91", "b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d", "be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", "c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", "de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", "e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", "e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77", "f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80", "f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e"]
coveralls = ["ab638e88d38916a6cedbf80a9cd8992d5fa55c77ab755e262e00b36792b7cd6d", "b2388747e2529fa4c669fb1e3e2756e4e07b6ee56c7d9fce05f35ccccc913aa0"]
@@ -256,6 +279,7 @@ py = ["06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", "50402
pycodestyle = ["682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766", "6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"]
pyflakes = ["08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f", "8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"]
pytest = ["7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e", "9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2"]
+pytest-cov = ["513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", "e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"]
requests = ["63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", "ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"]
six = ["70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", "832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"]
urllib3 = ["a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", "b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"]
diff --git a/pyproject.toml b/pyproject.toml
index bc1a443..b65f6c8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "scrmbl"
-version = "0.1.1"
+version = "1.0.0"
description = "Library for scrambled printing in terminal"
authors = ["Etienne Napoleone "]
readme = "README.md"
@@ -12,8 +12,13 @@ keywords = ["print", "library", "movie", "action", "scramble"]
[tool.poetry.dependencies]
python = "^3.5"
+click = "^7.0"
[tool.poetry.dev-dependencies]
pytest = "*"
flake8 = "^3.5"
coveralls = "^1.5"
+pytest-cov = "^2.6"
+
+[tool.poetry.scripts]
+scrmbl = 'scrmbl.cli:cli'
diff --git a/scrmbl/__init__.py b/scrmbl/__init__.py
index 4e7309b..54019b6 100644
--- a/scrmbl/__init__.py
+++ b/scrmbl/__init__.py
@@ -1,6 +1,5 @@
-from scrmbl.scrmbl import echo
-from scrmbl.scrmbl import charsets
+from scrmbl.main import echo
-__all__ = ['echo', 'charsets']
+__all__ = ['echo']
-__version__ = '0.1.1'
+__version__ = '1.0.0'
diff --git a/scrmbl/charsets.py b/scrmbl/charsets.py
deleted file mode 100644
index 6884c72..0000000
--- a/scrmbl/charsets.py
+++ /dev/null
@@ -1,12 +0,0 @@
-LETTERS_LOWER = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
- 'z']
-LETTERS_UPPER = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
- 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
- 'Z']
-FIGURES = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
-SPECIALS = ['_', '-', '#', '^', '$', '*', '+', '%', '&', '=', '!', '?', '/',
- '(', ')', '.', ',', '"', ';', '@']
-LETTERS = LETTERS_LOWER + LETTERS_UPPER
-ALPHANUMERICS = LETTERS + FIGURES
-ALL = ALPHANUMERICS + SPECIALS
diff --git a/scrmbl/cli.py b/scrmbl/cli.py
new file mode 100644
index 0000000..a8784ed
--- /dev/null
+++ b/scrmbl/cli.py
@@ -0,0 +1,42 @@
+import re
+import sys
+
+import click
+
+import scrmbl
+
+
+@click.command()
+@click.argument('message', default='')
+@click.option('-s', '--speed', type=click.FLOAT, default=0.05,
+ help='Time in seconds between prints. Default: 0.05')
+@click.option('-i', '--iterations', type=click.INT, default=2,
+ help='Number of iterations per character. Default: 2')
+@click.option('-c', '--charset',
+ type=click.Path(exists=True, allow_dash=True, dir_okay=False),
+ help='Set of chars to scramble.')
+@click.version_option(version=scrmbl.__version__)
+def cli(message: str, speed: float, iterations: int, charset: str) -> None:
+ """Scrmbl print the given message."""
+ # no text input
+ if not message:
+ # if no stdin or just '-c -'
+ if sys.stdin.isatty() or charset == '-':
+ raise click.UsageError('"MESSAGE" is empty. No argument or stdin.')
+ for line in sys.stdin:
+ message += line
+ message = _strip_ansi_colors(message)
+ if charset:
+ with click.open_file(charset) as f:
+ charset_content = f.read()
+ charset_content = charset_content.replace('\n', '')
+ else:
+ charset_content = None
+ scrmbl.echo(message, charset=charset_content, speed=speed,
+ iterations=iterations)
+
+
+def _strip_ansi_colors(message: str) -> str:
+ """Strip ANSI color codes"""
+ escape_codes = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
+ return escape_codes.sub('', message)
diff --git a/scrmbl/main.py b/scrmbl/main.py
new file mode 100644
index 0000000..72f2486
--- /dev/null
+++ b/scrmbl/main.py
@@ -0,0 +1,34 @@
+import random
+import string
+import time
+
+import click
+
+random.seed()
+
+ALL_CHARS = string.digits + string.ascii_letters + string.punctuation
+COLS, _ = click.get_terminal_size()
+
+
+def echo(message: str, charset: str = ALL_CHARS, speed: float = 0.05,
+ iterations: int = 2) -> None:
+ """Scrmbl print the given message."""
+ if not charset:
+ charset = ALL_CHARS
+ for line in message.split('\n'):
+ echoed = ''
+ for char in line:
+ for _ in range(iterations):
+ if char != ' ':
+ ran_char = random.choice(charset)
+ click.echo('\r{}{}'.format(echoed, ran_char), nl=False)
+ else:
+ click.echo('\r{}'.format(echoed), nl=False)
+ time.sleep(speed)
+ echoed += char
+ # wrap if line longer than console cols
+ if len(echoed) >= COLS - 1:
+ click.echo('\r' + echoed)
+ echoed = ''
+ if echoed:
+ click.echo('\r' + echoed)
diff --git a/scrmbl/scrmbl.py b/scrmbl/scrmbl.py
deleted file mode 100644
index 3aa2baa..0000000
--- a/scrmbl/scrmbl.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import random
-import time
-from typing import List
-
-from scrmbl import charsets
-
-random.seed()
-
-
-def echo(message: str, charset: List[str] = charsets.ALL, speed: float = 0.05,
- iterations: int = 2):
- "scrmbl print the given message"
- for line in message.split('\n'):
- echoed = ''
- for character in line:
- for iteration in range(iterations):
- print('\r{}{}'.format(echoed, random.choice(charset)), end='')
- time.sleep(speed)
- print('\r{}{}'.format(echoed, character), end='')
- echoed = echoed + character
- print()
diff --git a/tests/chars.txt b/tests/chars.txt
new file mode 100644
index 0000000..b5b9ef6
--- /dev/null
+++ b/tests/chars.txt
@@ -0,0 +1 @@
+abcdefg
diff --git a/tests/lipsum.txt b/tests/lipsum.txt
new file mode 100644
index 0000000..b4e6c1c
--- /dev/null
+++ b/tests/lipsum.txt
@@ -0,0 +1,17 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan arcu quis ex mollis suscipit. Sed non orci porttitor, tincidunt mauris id, volutpat diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam eget porta massa. Aliquam facilisis sit amet quam id sodales. Donec egestas pharetra pellentesque. Nam vestibulum dictum pharetra. Ut eget est at nibh condimentum sagittis ac a dui. Duis iaculis convallis rhoncus. Mauris maximus erat scelerisque, semper leo eget, rhoncus enim. Nulla ullamcorper in purus eget varius.
+
+Praesent imperdiet odio in massa egestas, a laoreet quam viverra. In hac habitasse platea dictumst. Suspendisse eu lobortis felis. Maecenas auctor purus risus, eget tempor turpis tincidunt at. Aliquam elementum feugiat ligula ac dictum. Aenean sit amet enim non lectus semper dignissim. Aenean posuere pretium faucibus. Suspendisse blandit est vel ultricies mollis. Sed pellentesque sem vel ullamcorper tempus. Fusce non nisi lorem. Phasellus at urna ut est viverra auctor. Vestibulum faucibus dapibus nisi nec mollis. Aenean commodo libero ipsum, ac mattis lectus dapibus vitae. Praesent urna massa, condimentum a sapien dapibus, fringilla gravida urna.
+
+Vestibulum gravida feugiat urna vitae commodo. Sed consequat mollis sem, ultrices ornare sapien dignissim ac. Mauris vestibulum ut nunc eget ultricies. Fusce vel fringilla arcu. Aenean felis ipsum, accumsan scelerisque ullamcorper ut, dignissim ac purus. Integer ornare, ligula sit amet condimentum hendrerit, turpis neque mattis erat, vitae fermentum lectus eros at urna. Sed nec dignissim felis, ac condimentum velit. Nam et tortor auctor, semper eros eget, lacinia dui. Maecenas id placerat mauris. Proin eget volutpat risus, sed ultrices tortor. Vivamus hendrerit congue dui, ut volutpat purus rhoncus sed. Maecenas consequat diam non metus dignissim faucibus. Donec sit amet posuere ex. In convallis placerat mi ac porttitor. Nullam blandit posuere mauris, et venenatis dui lobortis eget. Sed id est nec urna placerat pellentesque ac ut massa.
+
+Vivamus quis tristique metus. Fusce lobortis laoreet porta. Nam a luctus magna. Etiam eu tempor turpis, et scelerisque eros. Curabitur placerat mattis nibh sit amet lobortis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec dictum erat in justo sollicitudin suscipit. Nulla at odio quis magna posuere congue mollis non mi.
+
+Nam bibendum, lacus at molestie porttitor, risus ipsum egestas mauris, non vulputate ex erat nec diam. Nunc nec sollicitudin lectus. Aenean elementum sollicitudin augue, quis luctus dui mollis ut. Sed sed risus id enim gravida lobortis et in metus. Suspendisse eget sollicitudin risus. Praesent eget lacinia nunc. Maecenas laoreet nibh sit amet arcu hendrerit auctor. Proin in nulla in ex iaculis rutrum sed eu lectus. Vestibulum sollicitudin turpis ut odio aliquet, in gravida tellus sodales. Vestibulum vel tortor nec ante elementum venenatis in eu erat. Proin ornare semper ex a tempus. Etiam placerat orci ut tellus aliquet, a cursus nisl volutpat.
+
+Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris non ligula sapien. Donec eu felis sed diam suscipit accumsan. Etiam eu aliquet ligula, non tristique massa. Proin quis tempus mi, in hendrerit ex. Fusce vestibulum sodales mauris feugiat eleifend. Suspendisse at est accumsan, laoreet tortor quis, volutpat quam. Curabitur pellentesque nunc eu tempus cursus. Donec eget mollis enim, in fringilla eros. Curabitur malesuada eget orci eget faucibus. Sed id auctor velit. Vivamus ac diam quis eros pellentesque sollicitudin. Ut eu nisi ultricies justo finibus finibus.
+
+Morbi vel leo ut mi congue elementum. Donec scelerisque est sapien, ut malesuada arcu malesuada nec. Cras euismod ligula id leo posuere pellentesque. Ut et quam ut massa condimentum bibendum. Mauris venenatis fermentum nisl, quis convallis sem aliquam ac. Phasellus lobortis ac neque at interdum. Pellentesque non convallis magna. Vivamus ornare velit a leo interdum, a auctor nunc commodo. Donec lobortis lacus et nisl volutpat, at pharetra ex posuere.
+
+Nunc malesuada arcu non faucibus sodales. Morbi placerat quam ipsum, nec aliquam nulla vulputate at. Integer dignissim molestie faucibus. Mauris quis tortor porttitor sem pharetra ullamcorper. Vestibulum sodales varius efficitur. Quisque fringilla luctus massa vitae porttitor. Phasellus fermentum nibh eros, vitae condimentum felis finibus quis. In faucibus eget metus malesuada lobortis. Donec ut neque eget tellus imperdiet convallis nec eu tortor. Quisque felis purus, blandit eu fringilla eu, scelerisque a enim.
+
+Donec rhoncus lectus ex, vitae rhoncus sem aliquam in. Cras vitae facilisis justo. Nullam non fringilla arcu. In viverra lobortis lacus, a convallis nunc bibendum a. Nunc porta risus eu nisl varius euismod. Vestibulum sodales rutrum diam, nec elementum sapien suscipit non. Duis id turpis id justo aliquet lacinia at metus.
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 0000000..a98c32c
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,54 @@
+import re
+
+from click.testing import CliRunner
+
+from scrmbl.cli import cli
+
+
+def test_hello_world():
+ runner = CliRunner()
+ result = runner.invoke(cli, ['Hello, world!'])
+ assert result.exit_code == 0
+ assert result.output.split('\r')[-1] == 'Hello, world!\n'
+
+
+def test_input_stream():
+ with open('tests/lipsum.txt', 'r') as fin:
+ data = fin.read()
+ runner = CliRunner()
+ result = runner.invoke(cli, ['-s', '0'], input=data)
+
+ assert result.exit_code == 0
+
+ lines = iter(result.output.split('\r'))
+ # only retrieve longest lines i.e. full lines
+ filt = []
+ prev, curr = None, next(lines)
+ while curr:
+ if prev and len(curr) < len(prev):
+ filt.append(prev)
+
+ try:
+ prev, curr = curr, next(lines)
+ except StopIteration:
+ curr = None
+
+ for line in filt:
+ assert line.split('\n')[0] in data
+
+
+def test_invalid_cmd():
+ runner = CliRunner()
+ result = runner.invoke(cli, ['-c', '-'], input='abcdefg')
+ assert result.exit_code == 2
+ assert 'Usage:' in result.output
+ assert 'Error' in result.output
+
+
+def test_charset():
+ runner = CliRunner()
+ result = runner.invoke(cli, ['-c', 'tests/chars.txt', 'test'])
+ assert result.exit_code == 0
+ for line in result.output.split('\r'):
+ if line:
+ assert re.match(r'^[tes]{0,4}[abcdefg]?$', line)
diff --git a/tests/test_scrmbl.py b/tests/test_scrmbl.py
index bb6c912..9327938 100644
--- a/tests/test_scrmbl.py
+++ b/tests/test_scrmbl.py
@@ -1,9 +1,8 @@
import scrmbl
-from scrmbl import __version__
def test_version():
- assert __version__ == '0.1.1'
+ assert scrmbl.__version__ == '1.0.0'
def test_echo_single(capsys):