Last active
November 13, 2018 04:57
-
-
Save twolfson/e24af2d3d5424540492f to your computer and use it in GitHub Desktop.
Proof of concept to see how testing with ncurses works
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://docs.python.org/2/howto/curses.html | |
# Load in our dependencies | |
import curses | |
import sys | |
# Notes for future self: | |
# KeyboardInterrupt is generated by using an actual terminal | |
# Ctrl+C is interpretted into a signal | |
# We can actually type Ctrl+C via the `echo` command or by using `curses'` raw mode | |
# http://linux.die.net/man/3/cbreak | |
# We are running into a subprocess issue of testing `curses` | |
# I think it's likely easier to test the inner workings of the program via an API than to test its entirety | |
# Maybe it's possible to abstract the terminal integration to a very thin layer | |
# Which can be indepdendently tested | |
# Define our main function | |
def main(): | |
# Initialize our screen | |
# https://github.com/python-git/python/blob/715a6e5035bb21ac49382772076ec4c630d6e960/Lib/curses/__init__.py#L32-L33 | |
from StringIO import StringIO | |
sys.stdout = StringIO() | |
stdscr = curses.initscr() | |
pad = curses.newpad(100, 100) | |
# These loops fill the pad with letters; this is | |
# explained in the next section | |
for y in range(0, 100): | |
for x in range(0, 100): | |
try: | |
pad.addch(y, x, ord('a') + (x*x+y*y) % 26) | |
except curses.error: | |
pass | |
# Displays a section of the pad in the middle of the screen | |
pad.refresh(0, 0, 5, 5, 20, 75) | |
# Wait for someone to kill our script | |
while 1: | |
try: | |
pass | |
except KeyboardInterrupt: | |
curses.endwin() | |
sys.exit(0) | |
# If we are being invoked directly, call main | |
if __name__ == '__main__': | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Load in our dependencies | |
import subprocess | |
import time | |
# Define constants | |
SLEEP_INTERVAL = 0.1 | |
# Define our main function | |
def main(): | |
# Open files to output content to | |
STDOUT_PATH = '/tmp/gist-test-ncurses/stdout' | |
stdout_fd = open(STDOUT_PATH, 'w+') | |
stderr_fd = open('/tmp/gist-test-ncurses/stderr', 'w+') | |
# Start our child process | |
PIPE = subprocess.PIPE | |
child = subprocess.Popen(['python', 'main.py'], stdin=PIPE, stdout=stdout_fd, stderr=stderr_fd) | |
# Verify our process is running | |
print 'running', child.poll() | |
# Link with claims ofexperience but no idea... | |
# http://stackoverflow.com/questions/5579901/automated-test-tools-for-linux-ncurses | |
# Wait for output from our program | |
last_tell = 0 | |
time_since_last_output = 0.0 | |
def fn_loop(last_tell, time_since_last_output): | |
tell = stdout_fd.tell() | |
print 'wat', tell | |
if last_tell != tell: | |
print 'tmp_stdout', tell | |
last_tell = tell | |
else: | |
# If we have waited for 1 second, stop | |
if time_since_last_output > 1.0: | |
return | |
# Otherwise, sleep for a fraction of a second | |
time_since_last_output += SLEEP_INTERVAL | |
print 'sleeping for', SLEEP_INTERVAL | |
time.sleep(SLEEP_INTERVAL) | |
fn_loop(last_tell, time_since_last_output) | |
fn_loop(last_tell, time_since_last_output) | |
# print 'stderr', child.stderr.readline() | |
# Kill the process | |
# child.kill() | |
# print 'waiting for exit', child.wait() | |
# Close our files | |
stdout_fd.close() | |
stderr_fd.close() | |
# If we are being invoked directly, call main | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
+1 to these:
Edit:
I've actually been pondering that one day it would be great to have all the UI logic entirely separate from curses. That way we could switch to other terminal libraries or even some really basic desktop GUI (if needed). I used curses mainly since it's available by default and that's important for me. (I'm even running Suplemon on some 'legacy' servers with Python 2.6)