Commits: 2

Initiate the spec for tbb itself

The spec itself is very basic for now, but it triggered a cascade of changes.

There is a new Python interpreter at spec/self-check.py, and it needs to import tbb.py (just like samples/basic.py). I don't want to maintain two copies of this file or a symbolic link, so tbb.py was moved to spec/ directory. This necessitates samples/basic.py to import it from a sibling directory. It's possible if it's run via python -m, but then the module path is spec.tbb (calculated from root of the project).

index 6536f82..f61f2ac 100644
--- a/samples/basic.md
+++ b/samples/basic.md
@@ -1,5 +1,5 @@
=---
-interpreter: "python samples/basic.py"
+interpreter: "python -m samples.basic"
=---
=
=# Basic BDD suite
index 11158dd..45dfd6f 100644
--- a/samples/basic.py
+++ b/samples/basic.py
@@ -3,8 +3,8 @@
=import json
=import unittest
=
-import tbb
-from tbb import step, log
+import spec.tbb as tbb
+from spec.tbb import step, log
=
=
=# Nice assertions with helpful error messages
new file mode 100644
index 0000000..1de6e27
--- /dev/null
+++ b/spec/basic-usage.md
@@ -0,0 +1,14 @@
+---
+interpreter: "python -m spec.self-check"
+---
+
+# Basic Usage of the `tbb` program
+
+## Getting help
+
+  * Run the program with `--help` command line arguments
+  * The exit code should be `0`
+  * The output will contain `Usage: tbb`
+  * The output will contain `-h, +--help +Print help`
+  * The output will contain `-V, +--version +Print version`
+  * The output will contain `-v, +--verbose +Enable verbose logging`
new file mode 100644
index 0000000..70d8f9b
--- /dev/null
+++ b/spec/self-check.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+
+import os
+import re
+import shlex
+import subprocess
+import unittest
+from textwrap import dedent, indent
+
+import spec.tbb as tbb
+from spec.tbb import step, log
+
+
+base_command = "tbb"
+if os.environ.get ("CARGO"):
+    cargo_command = "cargo run --"
+    log.warning(f"Running inside Cargo. Will use `{cargo_command}` instead of `{base_command}`.")
+    base_command = cargo_command
+    
+tester = unittest.TestCase()
+completed = None # Hold results of running a command, for later inspection
+
+@step("Run the program with {0} command line arguments")
+def step_implementation_00(args: str, **kwargs):
+    # TODO: Consider augmenting tbb.py so it injects shared state into each step function.
+    global completed
+
+    command = shlex.split (base_command) + shlex.split (args)
+    completed = subprocess.run(command , stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+@step("The exit code should be {0}")
+def step_implementation_01(expected_code: int, **kwargs):
+    global completed
+
+    tester.assertEqual(expected_code, completed.returncode)  
+    # for line in completed.stdout.splitlines():
+    #     log.info(line)
+    # log.info(str(completed.stdout))
+    # completed = run()
+    # assert "cat" == "dog", "Obviously you need to replace this!"
+
+@step("The output will contain {0}")
+def step_implementation_02(pattern: str, **kwargs):
+    global completed
+
+    output = str(completed.stdout, "utf-8")
+
+    # The following gives unreadable output
+    # tester.assertRegex (output, expected_text)
+
+    assert re.search(pattern, output), dedent(f"""
+    
+    ``` regexp
+    {pattern} 
+    ```
+
+    --- not found in ---
+
+    ``` text
+    {indent_tail(output, "    ")}
+    ```
+    """)
+
+
+# TODO: Consider moving to tbb
+def indent_tail(text: str, indentation: str):
+    """Adds indentation to all lines except the first one
+
+    Useful when interpolating a multi-line string in a multiline f-string, like
+    this:
+
+    ``` python
+        dedent(f'''
+            Some static text
+            {indent(variable_multiline_text, "    ")}
+            More static text
+        ''')
+    ```
+
+    Notice that without this helper a newline in `variable_multiline_text` would
+    break `dedent` by setting the indentation level to 0.
+    """
+
+    lines = text.splitlines()
+    tail = indent(str.join("\n", lines[1:]), indentation)
+    return lines[0] + tail
+
+tbb.ready()
similarity index 100%
rename from samples/tbb.py
rename to spec/tbb.py

Specify the --version behavior

index 1de6e27..d691871 100644
--- a/spec/basic-usage.md
+++ b/spec/basic-usage.md
@@ -12,3 +12,11 @@ interpreter: "python -m spec.self-check"
=  * The output will contain `-h, +--help +Print help`
=  * The output will contain `-V, +--version +Print version`
=  * The output will contain `-v, +--verbose +Enable verbose logging`
+
+
+## Getting a version
+
+  * Run the program with `--version` command line arguments
+  * The exit code should be `0`
+  * The output will contain `tad-better-behavior \d+\.\d+\.\d+`
+