diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 341b13c..568c120 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.11 - name: Checkout code uses: actions/checkout@v2 - name: Run Unit Tests @@ -33,7 +33,7 @@ jobs: pip3 install wheel ./run.sh -b working-directory: ./ - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: wheel path: dist/shellwrap-*-py3-none-any.whl diff --git a/.gitignore b/.gitignore index d29f5d5..cbe462a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ lib #application -.python-*-history \ No newline at end of file +.python-*-history +__pycache__ diff --git a/run.sh b/run.sh index 9ccf6aa..5095a75 100755 --- a/run.sh +++ b/run.sh @@ -1,5 +1,10 @@ #!/bin/bash +run_init() +{ + pip3 install build +} + run_clean() { rm -rf build dist shellwrap.egg-info @@ -7,17 +12,19 @@ run_clean() run_build() { - python3 setup.py sdist bdist_wheel + #python3 setup.py sdist bdist_wheel + python3 -m build # the new way } run_install() { - pip3 install shellwrap-0.0.1-py3-none-any.whl + pip3 install dist/shellwrap-0.0.3-py3-none-any.whl } run_test() { - python3 -m unittest discover -s ./ -p '*test.py' + #python3 -m unittest discover -s ./test -p 'test*.py' + python3 -m unittest discover } run_lint() @@ -30,20 +37,36 @@ run_lint() # --ignore-patterns=".*\.md,.*\.sh,.*\.html,pylintrc,LICENSE,build,dist,tags,shellwrap.egg-info" } +run_help() +{ + fmt="%4s %s\\n" + printf "$fmt" flag meaning + printf "$fmt" -h help + printf "$fmt" -c clean + printf "$fmt" -b build + printf "$fmt" -I init + printf "$fmt" -i install + printf "$fmt" -t test + printf "$fmt" -l lint + printf "$fmt" -u uninstall + printf "$fmt" -v "set version" +} + # Process the command line arguments -while getopts "hcbitlu" opt +while getopts "hcbIitlu" opt do case ${opt} in h) run_help ;; c) run_clean ;; b) run_build ;; + I) run_init ;; i) run_install ;; t) run_test ;; l) run_lint ;; u) pip3 uninstall shellwrap ;; v) set_version $OPTARG ;; - *) help ; exit ;; + *) run_help ; exit ;; esac done diff --git a/example.py b/scripts/example.py similarity index 52% rename from example.py rename to scripts/example.py index 20c9ebf..00efa0f 100644 --- a/example.py +++ b/scripts/example.py @@ -1,7 +1,9 @@ from shellwrap import color +from shellwrap import file +from shellwrap import datetools from shellwrap import interactive from shellwrap import unix -from shellwrap import file +from shellwrap import net import argparse # ###################################### @@ -26,9 +28,9 @@ def initialize_enviornment(args): if args.color_off: environment["color"] = False if args.verbose: - environment["verbose"]=VMode.WARN + environment["verbose"]=1 if args.very_verbose: - environment["verbose"]=VMode.INFO + environment["verbose"]=3 return environment # ###################################### @@ -57,6 +59,37 @@ def process_actions(action=None, env:dict=None): some_task(action, env) return True +@color.print_red +@color.print_green +def log_this(item): + return item + +@color.bold +@color.green +def color_this(foo): + return foo + +@color.bold +@color.black_green +@color.underline +def blueit(text): + return text + +@color.green +@color.underline +def headline(text): + return text + +@unix.str_to_json +@unix.wrap_call +@unix.wrap_curl +def curl_test(url, what, proj): + return [url + what + proj, "-H", "Client-Id: test"] + +@net.str_to_json +def other_test(url): + return net.read(url)["text"] + # ###################################### #mark - Main @@ -69,22 +102,60 @@ def main(): world['do_action'] = do_action world['process_actions'] = process_actions - color.cprint(color.tcode.green, "Starting script", env) + print("This will go away") + color.cmd_clear_screen() + + color.cprint(color.tcode.green, "Starting script") if args.interactive: interactive.interactive(env, g=globals()) if args.user: interactive.user_commands(handler=process_actions, environment=env, g=globals()) + print(headline("Unix tests")) + result = unix.pipe(['echo', 'one', 'two', 'three'], ['wc', '-m']) + print(f"pipe result={result}.") + print(unix.ccurl('-H', 'Header: Value', 'https://github.com/jceaser/shellwrap.git')) - presult = unix.pipe(['echo', 'one', 'two', 'three'], ['wc', '-m']) - print(presult) + #print(headline("\nUnix Decorator tests")) + #print(curl_test('http://thomascherry.name/', + # '/cgi-bin/go.cgi', + # '?user=thomas&name=main&group=public')) - print(unix.ccurl('-H', 'Header: Value', 'https://github.com/jceaser/shellwrap.git')) + #color.cprint(color.tcode.red, "ending", env) + + print(headline("\nFile tests")) + print(file.read('.editorconfig')) + + print(headline("\nDecorator tests")) + print("Normal: %s" % log_this('hi, this is the decorator')) + print(color_this("some text")) + print(blueit("Make this blue and bold.")) + print(color.link("https://apple.com/", "apple.com")) + + #print(headline("\nURL tests")) + #url = 'http://thomascherry.name/cgi-bin/go.cgi?user=thomas&name=main&group=public' + #print(net.read(url)["text"]) + + #print(other_test(url)) + #print(net.rread(url).text) + + print(headline("Colorize tests")) + print(color.colorize(":rocket: This is my :red:red:end: text and this is my :green:green:end: text.")) + + color.cprint([color.tcode.green, color.tcode.underline], "my list text") + + print(' ; '.join(f"{i}={color.emoji[i]}" for i in color.emoji)) - color.cprint(color.tcode.red, "ending", env) + print(headline("Date tests")) + start: int = datetools.unix() + print("Now: ", datetools.now()) + print("Unix: ", datetools.unix()) + print("Today: ", datetools.today()) + print("Internal: ", datetools.now_internal()) + print("Durration: ", datetools.unix_difference(start)) - print(file.read_file('.editorconfig')) + print(color.colorize(":warn::blink::red: This is the end of the script :end:")) if __name__ == "__main__": main() diff --git a/scripts/show.py b/scripts/show.py new file mode 100644 index 0000000..a7398ec --- /dev/null +++ b/scripts/show.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +for i in range(30, 37 + 1): + print("\033[%dm%d\t\t\033[%dm%d" % (i, i, i + 60, i + 60)) + +print("\033[39m\\033[49m - Reset color") +print("\\033[2K - Clear Line") +print("\\033[;H or \\033[;f - Put the cursor at line L and column C.") +print("\\033[A - Move the cursor up N lines") +print("\\033[B - Move the cursor down N lines") +print("\\033[C - Move the cursor forward N columns") +print("\\033[D - Move the cursor backward N columns\n") +print("\\033[2J - Clear the screen, move to (0,0)") +print("\\033[K - Erase to end of line") +print("\\033[s - Save cursor position") +print("\\033[u - Restore cursor position\n") +print("\\033[4m - Underline on") +print("\\033[24m - Underline off\n") +print("\\033[1m - Bold on") +print("\\033[21m - Bold off") diff --git a/setup.py b/setup.py index a249599..92e8cb7 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -VERSION = '0.0.1' +VERSION = '0.0.3' DESCRIPTION = 'Scripting Tools' LONG_DESCRIPTION = 'A set of tools to make it easy to write unix scripts' diff --git a/shellwrap/color.py b/shellwrap/color.py index a4bbb8d..3767500 100755 --- a/shellwrap/color.py +++ b/shellwrap/color.py @@ -8,31 +8,16 @@ # template modified 2021-09-02 -""" template script for future scripts """ +""" Terminal codes for drawing colors and styles on text """ #mark - Imports from enum import Enum #Creating Enums -#import argparse #command line parsing -#import code #interactive shell -#import os #file handling -#import re #filter in man() -#import readline #interactive shell -#import subprocess #calling unix commands -#import sys #exiting +import re # ############################################################################## #mark - Utility functions - Leave these alone -class VMode(Enum): - """ Verbose Mode Enums, higher values print less""" - FATAL = -8 # always print - ERROR = 0 - NORMAL = 1 - WARN = 2 - INFO = 4 - DEBUG = 8 - class TerminalCode(dict): """ A custom dictionary for storing terminal color codes that allows for value @@ -46,34 +31,119 @@ def __init__(self, data): """ super().__init__() for key, value in data.items(): - self[key] = self[value[2:]] if value.startswith('->') else value + self[key] = value def __getattr__ (self, attr): """ Allow items to be access with dot notation. """ - return self.get(attr, '\033[0m') - -tcode = TerminalCode({'red':'\033[0;31m', - 'green': '\033[0;32m', - 'yellow': '\033[0;33m', - 'blue': '\033[0;34m', - 'white': '\033[0;37m', - 'bold': '\033[1m', - 'underline': '\033[4m', - #'nc': '\033[0m', # No Color - # now define duplicates - VMode.FATAL: '->red', - VMode.ERROR: '->red', - VMode.NORMAL: '->white', - VMode.WARN: '->yellow', - VMode.INFO: '->blue', - VMode.DEBUG: '->underline' + color_code = self.get(attr.replace('_', '-'), '\033[0m') + return color_code + + def escape(self, code) -> str: + """ Take a TerminalCode and wrap it in terminal escape code. """ + return f'\033[{code}m' + + def full(self, fg, bg): + fgc = self.get(fg, "0") + bgc = self.get(bg, "0") + return f'\033[{fgc};{bgc}m' + +#https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences + +"""Colors for the following schemas: +* RGB - Red, Green, Blue +* RYG - Red, Yellow, Green +* CMYK - Cyan, Magenta, Yellow, Black +""" +tcode = TerminalCode({'none': '0', 'end': '0', + 'bold': '1', + 'faint': '2', + 'italix': '3', #not well supported + 'underline': '4', + 'slow': '5', 'blink': '5', + 'fast': '6', #not well supported + 'inverse': '7', + 'hide': '8', + + 'nc': '\033[0m', + 'on-bold': '\033[1m', + 'on-faint': '\033[2m', + 'on-italix': '\033[3m', #not well supported + 'on-underline': '\033[4m', + 'on-slow': '\033[5m', + 'on-fast': '\033[6m', #not well supported + 'on-inverse': '\033[7m', + 'on-hide': '\033[8m', + + 'off-bold': '\033[21m', + 'off-faint': '\033[22m', + 'off-italix': '\033[23m', #not well supported + 'off-underline': '\033[24m', + 'off-slow': '\033[25m', + 'off-fast': '\033[26m', #not well supported + 'off-inverse': '\033[27m', + 'off-hide': '\033[28m', + + 'black': '30', + 'red':'31', + 'green': '32', + 'yellow': '33', + 'blue': '34', + 'magenta': '35', + 'cyan': '36', + 'white': '37', + + 'back-black':'40', + 'back-red':'41', + 'back-green': '42', + 'back-yellow': '43', + 'back-blue': '44', + 'back-magenta': '45', + 'back-cyan': '46', + 'back-white': '47', + + 'bright-black' : '90', + 'bright-red' : '91', + 'bright-green' : '92', + 'bright-yellow': '93', + 'bright-blue' : '94', + 'bright-magenta' : '95', + 'bright-cyan' : '96', + 'bright-white' : '97', + + 'back-bright-black': '100', + 'back-bright-red': '101', + 'back-bright-green': '102', + 'back-bright-yellow': '103', + 'back-bright-blue': '104', + 'back-bright-magenta': '105', + 'back-bright-cyan': '106', + 'back-bright-white': '107', + + 'clear-screen': '\033[2J', + 'clear-line': '\033[2K', + 'clear-to-end': '\033[K', + 'position-save': '\033[s', + 'position-restore': '\033[u' }) -def is_verbose(environment, verbose): - """ True if the environment is in verbose mode; Can print in verbose mode """ - return verbose.value <= environment.get("verbose", VMode.WARN).value +#emoji: TerminalCode = TerminalCode({':rocket:': '๐Ÿš€'}) +emoji: dict[str,str] = {'none': '', + 'airship':'๐ƒŒ', + 'bomb': '๐Ÿ’ฃ', + 'chequered': '๐Ÿ', + 'degree': 'ยฐ', + 'firecracker': '๐Ÿงจ', + 'flag': '๐Ÿณ๏ธ', + 'pirate': '๐Ÿดโ€โ˜ ๏ธ', + 'platform': '๐™', + 'post': '๐Ÿšฉ', + 'rocket': '๐Ÿš€', + 'sub': '๐ƒ', + 'unicorn': '๐Ÿฆ„', + 'warn': 'โš ๏ธ' +} -def cprint(color:str, content:str, environment:dict=None, verbose:VMode=VMode.NORMAL): +def cprint(color: str | list[str], content:str): """ Color Print, print out text in the requested color, but respect the verbose and color modes of the environment variable. @@ -90,23 +160,131 @@ def cprint(color:str, content:str, environment:dict=None, verbose:VMode=VMode.NO Return: None """ - if environment is None: - environment = {} - if is_verbose(environment, verbose): - if environment.get("color", True): - print ("{}{}{}".format(color, content, tcode.nc)) - else: - print ("{}".format(content)) -def vcprint(verbose:VMode, content:str, environment:dict=None): + if isinstance(color, list): + colors = ";".join(color) + print(f"\033[{colors}m{content}\033[0m") + else: + print ("{}{}{}".format(tcode.escape(color), content, tcode.nc)) + +def encoder(color: str, content: str): """ - Verbose Color Printing: - Decided what color to print out for the user, based on verbose level + Take a color code and text content, either with or without escape code, and return a printable + escape sequence. + """ + if color.startswith('\033['): + return "{}{}{}".format(color, content, tcode.nc) + else: + return f"\033[{color}m{content}\033[0m" - Parameters: - * verbose - level for print context - * content - text to print out - * environment - application settings +def link(link:str, text:str): + """ Take an html link and link text and return a printable escape sequence. """ + return '\033]8;;{}\a{}\033]8;;\a'.format(link, text) + +def colorize(text: str): """ - cprint (tcode.get(verbose, tcode.white), content, environment, verbose) + Parse the input text and apply color formatting based on the tags. + + Tags should be in the format :color: where color is the name of the color. + The :end tag is used to reset the color. + + Example: + ":red:Hello :green:World:end" will color "Hello" in red and "World" in green. + """ + # Find all color tags in the text + tags = re.findall(r':(\w+):', text) + + # Replace each tag with its corresponding ANSI color code + for tag in tags: + if tag in tcode: + text = text.replace(f':{tag}:', f'\033[{tcode[tag]}m') + elif tag in emoji: + text = text.replace(f':{tag}:', emoji[tag]) + else: + # If the tag is not recognized, leave it as is + pass + return text + +# ############################################################################## +# decorators - experimental + +def black(foo): + return lambda c : encoder(tcode.black, foo(c)) + +def red(foo): + return lambda c : encoder(tcode.red, foo(c)) + +def black_green(foo): + color = tcode.full("black", "backgreen") + return lambda c : encoder(color, foo(c)) + +def green(foo): + return lambda c : encoder(tcode.green, foo(c)) + +def blue(foo): + return lambda c : encoder(tcode.blue, foo(c)) + +def bold(foo): + return lambda c : encoder(tcode.bold, foo(c)) + +def underline(foo): + return lambda c : encoder(tcode.underline, foo(c)) + +def print_red(function): + def inner(*args): + ret = function(*args) + cprint(tcode.red, ret) + return ret + return inner + +def print_green(function): + def inner(*args): + ret = function(*args) + cprint(tcode.green, ret) + return ret + return inner + +def print_blue(function): + def inner(*args): + ret = function(args) + cprint(tcode.blue, ret) + return ret + return inner + +# ############################################################################## +# terminal commands + +def command(code: str) -> None: + print (code, end='') + +def cmd_clear_screen(): + command(tcode.clear_screen) + +def cmd_clear_line(): + command(tcode.clear_line) + +def cmd_clear_end_line(): + command(tcode.clear_to_end) + +def cmd_save_position(): + command(tcode.position_save) + +def cmd_restore_position(): + command(tcode.position_restore) + +def cmd_move(num: int, direction: str) -> None: + direction_normalized: str = direction.upper() + action: str = '' + match direction_normalized: + case "UP": + action = "A" + case "DOWN": + action = "B" + case "RIGHT": + action = "C" + case "LEFT": + action = "D" + command(f'\033[{str(num)}{action}') +def cmd_move_to(line: int, column: int): + command(f'\033[{line};{column}H') diff --git a/shellwrap/datetools.py b/shellwrap/datetools.py index 9b8f733..5e40123 100644 --- a/shellwrap/datetools.py +++ b/shellwrap/datetools.py @@ -6,19 +6,32 @@ # template modified 2021-09-02 -""" template script for future scripts """ +""" Functions for getting Date and Time values """ #mark - Imports import datetime +import time # ###################################### #mark date functions -def now(): +def now_internal() -> datetime: + """ In testing, this one function can be Mocked to stop time """ + return datetime.datetime.now() + +def now() -> str: """ Return a string with the current date and time formated in ISO""" - return datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + return now_internal().strftime("%Y-%m-%dT%H:%M:%S") -def today(): +def today() -> str: """ Return a string with the current date formated in ISO""" - return datetime.datetime.now().strftime("%Y-%m-%d") + return now_internal().strftime("%Y-%m-%d") + +def unix() -> int: + """ unix time stamp """ + return int(time.time()) + +def unix_difference(start: int) -> int: + """ different from a unix start time stamp and now """ + return int(time.time()) - start diff --git a/shellwrap/file.py b/shellwrap/file.py index 29d7a4c..7a7c37a 100755 --- a/shellwrap/file.py +++ b/shellwrap/file.py @@ -8,23 +8,40 @@ # template modified 2021-09-02 -""" template script for future scripts """ +""" Functions for managing files, cRUD """ #mark - Imports -#from enum import Enum #Creating Enums -#import argparse #command line parsing -#import code #interactive shell import os #file handling -#import re #filter in man() -#import readline #interactive shell -#import subprocess #calling unix commands -#import sys #exiting # ###################################### #mark File Tools -def read_file(path:str=None): +def exists(path:str=None): + """ + Tests if a file or directory exists + Parameters: + path (string): full path to file or directory to test for + Returns: + True if path exists, false otherwise + """ + path=os.path.realpath(__file__[:-2]+"txt") if path is None else os.path.expanduser(path) + #return os.path.isfile(path) + return os.path.exists(path) + +#Create +def create(path: str = None): + """ + Create an empty file (if it doesn't exist already) + Parameters: + path (string): path to file to create + """ + path = os.path.realpath(__file__[:-2] + "txt") if path is None else os.path.expanduser(path) + with open(path, "w"): + pass + +#Read +def read(path:str=None): """ Read and return the contents of a file Parameters: @@ -39,8 +56,8 @@ def read_file(path:str=None): text = file.read().strip() file.close() return text - -def write_file(text:str, path:str=None): +# Update +def write(text:str, path:str=None): """ Write (creating if need be) file and set it's content Parameters: @@ -51,3 +68,13 @@ def write_file(text:str, path:str=None): with open(path, "w+") as cache: cache.write(text) cache.close() +# Delete +def delete(path:str=None): + """ + Delete file and set it's content + Parameters: + path (string): path to file to write + text (string): content for file + """ + path=os.path.realpath(__file__[:-2]+"txt") if path is None else os.path.expanduser(path) + os.remove(path) diff --git a/shellwrap/net.py b/shellwrap/net.py new file mode 100644 index 0000000..82b6b96 --- /dev/null +++ b/shellwrap/net.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +""" Functions for making HTTP requests """ + +#mark - Imports + +import json +import urllib.request +#import requests + +def str_to_json(foo): + return lambda *flags : json.loads(foo(*flags)) + +def read(url): + ret = "" + try: + resp = urllib.request.urlopen(url) + ret = resp.read() + except urllib.error.HTTPError as e: + ret = 'HTTPError: {} - {}'.format(e.code, e.reason) + ret = {'status': e.code, + 'headers': e.headers.items(), + 'text': e.read().decode()} + return ret diff --git a/shellwrap/unix.py b/shellwrap/unix.py index 3a510a0..9d66733 100755 --- a/shellwrap/unix.py +++ b/shellwrap/unix.py @@ -8,18 +8,12 @@ # template modified 2021-09-02 -""" template script for future scripts """ +""" Functions to make calling Unix apps easy """ #mark - Imports -#from enum import Enum #Creating Enums -#import argparse #command line parsing -#import code #interactive shell -#import os #file handling -#import re #filter in man() -#import readline #interactive shell +import json import subprocess #calling unix commands -#import sys #exiting # ###################################### #mark calling unix commands @@ -47,6 +41,16 @@ def pipe(*cmd_lists): #print (f"return:{pipe_result.returncode}") return pipe_result.stdout.decode('utf-8') +def wrap_curl(foo): + """Wrap a list of parameters""" + return lambda *flags : curl(*foo(*flags)) + +def wrap_call(foo): + return lambda *flags : call(*foo(*flags)) + +def str_to_json(foo): + return lambda *flags : json.loads(foo(*flags)) + def curl(*flags): """ Build a curl command list which can be passed to pipe() or call() """ cmd = ["curl", "-s", '-A', 'tcherry-script'] diff --git a/shellwrap/util.py b/shellwrap/util.py new file mode 100644 index 0000000..8d46e61 --- /dev/null +++ b/shellwrap/util.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +""" General functions of no specific category """ + +#mark - Imports + +import json + +#mark - functions + +def str_to_json(foo): + return lambda *flags : json.loads(foo(*flags)) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/shellwrap/__init__.py b/test/shellwrap/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/shellwrap/test_color.py b/test/shellwrap/test_color.py new file mode 100644 index 0000000..509c281 --- /dev/null +++ b/test/shellwrap/test_color.py @@ -0,0 +1,53 @@ +#from unittest.mock import Mock +#from unittest.mock import patch +import unittest + +#import urllib.error as urlerr + +#import test.util as tutil + +import shellwrap.color as color + +class TestColor(unittest.TestCase): + """Test suit for Search API""" + + def pattern_maker_color(self, color, content): + return '\033[0;{}m{}\033[0m'.format(color, content) + def pattern_maker_style(self, color, content): + return '{}{}\033[0m'.format(color, content) + + # ********************************************************************** + # Tests + + def test_tcode(self): + def are(code_name, iscolor=True): + expected_code = color.tcode[code_name] + expected_esc = expected_code # assume style, not color + if iscolor: + expected_esc = '\x1b[0;{}m'.format(expected_code) + expected_full = '\x1b[{};{}m'.format(expected_code, expected_code) + self.assertEqual(expected_esc, color.tcode.__getattr__(code_name), "[] test") + self.assertEqual(expected_code, color.tcode.raw(code_name), "raw() test") + self.assertEqual(expected_full, color.tcode.full(code_name, code_name), "Full() test") + + are("red") + are("green") + are("backgreen") + are("bright_yellow") + are("underline", False) + are("off_inverse", False) + + def test_red(self): + src = lambda a : a + self.assertEqual("\x1b[0;31mtest\x1b[0m", color.red(src)("test")) + self.assertEqual(self.pattern_maker_color(color.tcode.raw('red'), "test"), + color.red(src)("test")) + + def test_link(self): + self.assertEqual('\x1b]8;;http://example.org\x07Example\x1b]8;;\x07', + color.link("http://example.org", "Example")) + + def test_other(self): + expected = self.pattern_maker_style(color.tcode.raw('hide'), "test") + actual = color.encoder(color.tcode.hide, "test") + self.assertEqual(expected, actual) diff --git a/test/shellwrap/test_time.py b/test/shellwrap/test_time.py new file mode 100644 index 0000000..7bb0698 --- /dev/null +++ b/test/shellwrap/test_time.py @@ -0,0 +1,43 @@ +from unittest.mock import Mock +from unittest.mock import patch +from unittest.mock import MagicMock + +import unittest +import datetime +import shellwrap.datetools as dt + +class TestTime(unittest.TestCase): + """Test suit for date-tools API""" + + def fixed_date_2024_02_14(self): + return 1707930000 + + def fixed_datetime(self): + return datetime.datetime(2024, 2, 14, 12, 0, 0, 0) + + # ********************************************************************** + # Tests + + def test_now(self): + dt.now_internal = MagicMock(return_value=self.fixed_datetime()) + self.assertEqual("2024-02-14T12:00:00", dt.now(), "now is broken") + + def test_today(self): + dt.now_internal = MagicMock(return_value=self.fixed_datetime()) + self.assertEqual("2024-02-14", dt.today(), "today is broken") + + @patch('time.time') + def test_unix(self, mocked_time_time): + mocked_time_time.return_value = self.fixed_date_2024_02_14() + expected = self.fixed_date_2024_02_14() + actual = dt.unix() + self.assertEqual(expected, value) + + @patch('time.time') + def test_unix(self, mocked_time_time): + mocked_time_time.return_value = self.fixed_date_2024_02_14() + + expected = 1000 + start = self.fixed_date_2024_02_14() - expected + actual = dt.unix_difference(start) + self.assertEqual(expected, actual, "date math is wrong") diff --git a/test/shellwrap/test_util.py b/test/shellwrap/test_util.py new file mode 100644 index 0000000..38e5eec --- /dev/null +++ b/test/shellwrap/test_util.py @@ -0,0 +1,21 @@ +#from unittest.mock import Mock +#from unittest.mock import patch +import unittest + +#import urllib.error as urlerr +#import test.util as tutil + +import shellwrap.util as util + +class TestColor(unittest.TestCase): + + def test_json(self): + """ Setup a function to cgall str_to_json on """ + @util.str_to_json + def foo(data): + """This function could load a file and return a JSON string""" + return "{\"Data\": \"%s\"}" % data + + expected = {'Data': 'test'} + actual = foo("test") + self.assertEqual(expected, actual)