#!/user/bin/env python3

"""Test clipboard utility 'cb'.

Call out to 'cb' utility with various usages. Originally intended to run with
py.test, except running with py.test causes a problem where the clipboard
doesn't actually get set during the test, and I have zero idea why.

What's stranger, if you run the debugger (left commented out in set_clipboard
for now) it behaves correctly, even if you just immediately (c)ontinue.

So, I implemented a main that runs the tests manually, which behaves correctly.

It also works in Nose! Example outputs:

$ py.test -v test_cb.py
...
test_cb.py::test_default FAILED
test_cb.py::test_pipe_set FAILED
test_cb.py::test_pipe_get FAILED
test_cb.py::test_argument_set FAILED
test_cb.py::test_set_with_redirect FAILED

$ nosetests -v test_cb.py
Test default usage. ... ok
Test setting clipboard with value piped to cb. ... ok
Test getting clipboard with value piped from cb. ... ok
Test setting clipboard with an argument. ... ok
Test setting clipboard with file redirect. ... ok

$ python3 test_cb.py
Running functions: ['test_argument_set', 'test_default', 'test_pipe_get', 'test_pipe_set', 'test_set_with_redirect']
Running test_argument_set
Result is 'baz', test_str is 'baz' =? True
Running test_default
Result is 'foo', test_str is 'foo' =? True
Running test_pipe_get
Result is 'bar', test_str is 'bar' =? True
Running test_pipe_set
Result is 'bar', test_str is 'bar' =? True
Running test_set_with_redirect
Result is 'qux', test_str is 'qux' =? True
"""

import inspect
import tempfile
from subprocess import check_call as cc, check_output as co

# CB = 'xerox'
CB = 'cb'

# get and set clipboard utility functions. These depend on cb behavior being
# correct in the first place, but could potentially be replaced with an
# independent method
def set_clipboard(test_str):
    # import pdb; pdb.set_trace()
    cc([CB, test_str])


def get_clipboard():
    value = co(CB).decode()
    if CB == 'xerox':
        value = value.rstrip()

    return value


def call(cmd):
    args = {'shell': True, 'executable': 'bash'} if isinstance(cmd, str) else {}
    # print(f'Executing {cmd}, {args}')
    value = co(cmd, **args).decode()
    if CB == 'xerox':
        value = value.rstrip()

    return value


def test_default():
    """Test default usage.

    Example:
        "foo" is in clipboard
        $ cb
        foo
    """
    test_str = 'foo'
    set_clipboard(test_str)
    result = call(CB)
    print(f'Result is {result!r}, test_str is {test_str!r} =? {result == test_str!r}')
    assert result == test_str


def test_pipe_set():
    """Test setting clipboard with value piped to cb.

    Example:
        $ echo bar | cb
        $ cb
        bar
    """
    # import pdb; pdb.set_trace()
    test_str = 'bar'
    call(f'echo -n "{test_str}" | {CB}')
    result = get_clipboard()
    print(f'Result is {result!r}, test_str is {test_str!r} =? {result == test_str!r}')
    assert result == test_str


def test_pipe_get():
    """Test getting clipboard with value piped from cb.

    Example:
        $ cb | cat
        $ cb
        bar
    """
    test_str = 'bar'
    set_clipboard(test_str)
    result = call(f'{CB} | cat')
    print(f'Result is {result!r}, test_str is {test_str!r} =? {result == test_str!r}')
    assert result == test_str


def test_argument_set():
    """Test setting clipboard with an argument.

    Example:
        $ cb baz
        $ cb
        baz
    """
    test_str = 'baz'
    call(f'{CB} {test_str}')
    result = get_clipboard()
    print(f'Result is {result!r}, test_str is {test_str!r} =? {result == test_str!r}')
    assert result == test_str


def test_set_with_redirect():
    """Test setting clipboard with file redirect.

    Example:
        $ cb <testfile
    """
    test_str = 'qux'
    tf = tempfile.NamedTemporaryFile()
    tf.write(test_str.encode())
    tf.flush()
    call(f'{CB} <{tf.name}')
    tf.close()
    result = get_clipboard()
    print(f'Result is {result!r}, test_str is {test_str!r} =? {result == test_str!r}')
    assert result == test_str


if __name__ == '__main__':
    test_funcs = {
        name: item for name, item in globals().items()
        if inspect.isfunction(item) and name.startswith('test_')
    }
    print(f"Running functions: {sorted(test_funcs)}")

    for name, func in sorted(test_funcs.items()):
        try:
            print(f"Running {name}")
            func()
        except:
            print("###Assertion failed")

@@ -55,1444 +55,77 @@
 '.%0A%0A
-Call out to 'cb' utility with various usages. Originally intended to run with%0Apy.test, except running with py.test causes a problem where the clipboard%0Adoesn't actually get set during the test, and I have zero idea why.%0A%0AWhat's stranger, if you run the debugger (left commented out in set_clipboard%0Afor now) it behaves correctly, even if you just immediately (c)ontinue.%0A%0ASo, I implemented a main that runs the tests manually, which behaves correctly.%0A%0AIt also works in Nose! Example outputs:%0A%0A$ py.test -v test_cb.py%0A...%0Atest_cb.py::test_default FAILED%0Atest_cb.py::test_pipe_set FAILED%0Atest_cb.py::test_pipe_get FAILED%0Atest_cb.py::test_argument_set FAILED%0Atest_cb.py::test_set_with_redirect FAILED%0A%0A$ nosetests -v test_cb.py%0ATest default usage. ... ok%0ATest setting clipboard with value piped to cb. ... ok%0ATest getting clipboard with value piped from cb. ... ok%0ATest setting clipboard with an argument. ... ok%0ATest setting clipboard with file redirect. ... ok%0A%0A$ python3 test_cb.py%0ARunning functions: %5B'test_argument_set', 'test_default', 'test_pipe_get', 'test_pipe_set', 'test_set_with_redirect'%5D%0ARunning test_argument_set%0AResult is 'baz', test_str is 'baz' =? True%0ARunning test_default%0AResult is 'foo', test_str is 'foo' =? True%0ARunning test_pipe_get%0AResult is 'bar', test_str is 'bar' =? True%0ARunning test_pipe_set%0AResult is 'bar', test_str is 'bar' =? True%0ARunning test_set_with_redirect%0AResult is 'qux', test_str is 'qux' =? True
+Run with nose or pytest -s (because 'cb' requires normal system fds).
 %0A%22%22%22
@@ -222,23 +222,8 @@
 co%0A%0A
-# CB = 'xerox'%0A
 CB =
@@ -432,42 +432,8 @@
 r):%0A
-    # import pdb; pdb.set_trace()%0A
     
@@ -474,31 +474,30 @@
 oard():%0A    
-value =
+return
  co(CB).deco
@@ -505,79 +505,8 @@
 e()%0A
-    if CB == 'xerox':%0A        value = value.rstrip()%0A%0A    return value%0A
 %0A%0Ade
@@ -607,151 +607,39 @@
     
-# print(f'Executing %7Bcmd%7D, %7Bargs%7D')%0A    value = co(cmd, **args).decode()%0A    if CB == 'xerox':%0A        value = value.rstrip()%0A%0A    return value
+return co(cmd, **args).decode()
 %0A%0A%0Ad
@@ -836,95 +836,8 @@
 CB)%0A
-    print(f'Result is %7Bresult!r%7D, test_str is %7Btest_str!r%7D =? %7Bresult == test_str!r%7D')%0A
     
@@ -1014,42 +1014,8 @@
 %22%22%22%0A
-    # import pdb; pdb.set_trace()%0A
     
@@ -1105,95 +1105,8 @@
 d()%0A
-    print(f'Result is %7Bresult!r%7D, test_str is %7Btest_str!r%7D =? %7Bresult == test_str!r%7D')%0A
     
@@ -1362,95 +1362,8 @@
 t')%0A
-    print(f'Result is %7Bresult!r%7D, test_str is %7Btest_str!r%7D =? %7Bresult == test_str!r%7D')%0A
     
@@ -1610,95 +1610,8 @@
 d()%0A
-    print(f'Result is %7Bresult!r%7D, test_str is %7Btest_str!r%7D =? %7Bresult == test_str!r%7D')%0A
     
@@ -1951,522 +1951,30 @@
     
-print(f'Result is %7Bresult!r%7D, test_str is %7Btest_str!r%7D =? %7Bresult == test_str!r%7D')%0A    assert result == test_str%0A%0A%0Aif __name__ == '__main__':%0A    test_funcs = %7B%0A        name: item for name, item in globals().items()%0A        if inspect.isfunction(item) and name.startswith('test_')%0A    %7D%0A    print(f%22Running functions: %7Bsorted(test_funcs)%7D%22)%0A%0A    for name, func in sorted(test_funcs.items()):%0A        try:%0A            print(f%22Running %7Bname%7D%22)%0A            func()%0A        except:%0A            print(%22###Assertion failed%22)
+assert result == test_str
 %0A

Update cb tests