Repository: sandialabs/reverse_argparse (language: python)

Issue:
Run examples in CI
Add a step to the continuous integration workflow to run all the examples after installing the package.  Not sure if/how we'll want to check the output.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 2e4ecd1..4bdc318 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -35,17 +35,17 @@ jobs:
             -r example/requirements.txt \
             -r test/requirements.txt
 
+      - name: Test install
+        run: python3 -m pip install .
+
       - name: Test with pytest
-        run: python3 -m pytest --cov=reverse_argparse test/
+        run: python3 -m pytest --cov=reverse_argparse example/ test/
 
       - name: Upload coverage reports to Codecov
         uses: codecov/codecov-action@v3
         env:
           CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
 
-      - name: Test install
-        run: python3 -m pip install .
-
       - name: Check documentation spelling
         run: make spelling
         working-directory: ./doc
diff --git a/example/basic.py b/example/basic.py
old mode 100644
new mode 100755
diff --git a/example/default_values.py b/example/default_values.py
old mode 100644
new mode 100755
diff --git a/example/post_processing.py b/example/post_processing.py
old mode 100644
new mode 100755
diff --git a/example/pretty_printing.py b/example/pretty_printing.py
old mode 100644
new mode 100755
diff --git a/example/relative_references.py b/example/relative_references.py
old mode 100644
new mode 100755
diff --git a/example/subparsers.py b/example/subparsers.py
old mode 100644
new mode 100755


Test patch:
diff --git a/example/test_examples.py b/example/test_examples.py
new file mode 100755
index 0000000..719ed55
--- /dev/null
+++ b/example/test_examples.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+"""Run all the examples and ensure their output is correct."""
+import re
+import shlex
+import subprocess  # nosec B404
+from datetime import datetime, timedelta
+from pathlib import Path
+
+
+def test_basic() -> None:
+    example = Path(__file__).parent / "basic.py"
+    result = subprocess.run(
+        [example, "--foo", "bar"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        result.stdout
+        == """
+The effective command line invocation was:
+basic.py --foo bar
+""".lstrip()
+    )
+
+
+def test_default_values() -> None:
+    example = Path(__file__).parent / "default_values.py"
+    result = subprocess.run(
+        [example, "--foo", "bar"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        result.stdout
+        == """
+The effective command line invocation was:
+default_values.py --foo bar --bar spam --baz 42
+""".lstrip()
+    )
+
+
+def test_relative_references() -> None:
+    example = Path(__file__).parent / "relative_references.py"
+    result = subprocess.run(
+        [example, "--src", "bar.txt"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        """
+The effective command line invocation was:
+relative_references.py --bar spam --baz 42 --src
+""".strip()
+        in result.stdout
+    )
+    assert re.search(r"--src /\S+/bar\.txt", result.stdout)
+
+
+def test_post_processing() -> None:
+    example = Path(__file__).parent / "post_processing.py"
+    result = subprocess.run(
+        [example, "--before", "'30 minutes ago'"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        """
+The effective command line invocation was:
+post_processing.py --bar spam --baz 42 --before
+""".strip()
+        in result.stdout
+    )
+    thirty_miutes_ago = datetime.now() - timedelta(minutes=30)
+    time_from_example = datetime.strptime(
+        shlex.split(result.stdout)[-1], "%Y-%m-%d %H:%M:%S.%f"
+    )
+    assert thirty_miutes_ago - time_from_example < timedelta(seconds=1)
+
+
+def test_pretty_printing() -> None:
+    example = Path(__file__).parent / "pretty_printing.py"
+    result = subprocess.run(
+        [example, "--foo", "eggs", "--src", "file.txt", "--before", "'today'"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        """
+The effective command line invocation was:
+pretty_printing.py \\
+    --foo eggs \\
+    --bar spam \\
+    --baz 42 \\
+""".strip()
+        in result.stdout
+    )
+    assert re.search(r"--src /\S+/file\.txt", result.stdout)
+    today = datetime.now()
+    time_from_example = datetime.strptime(
+        shlex.split(result.stdout.splitlines()[-1])[-1],
+        "%Y-%m-%d %H:%M:%S.%f",
+    )
+    assert today - time_from_example < timedelta(seconds=1)
+
+
+def test_subparsers() -> None:
+    example = Path(__file__).parent / "subparsers.py"
+    result = subprocess.run(
+        [example, "foo", "--one", "eggs"],
+        capture_output=True,
+        check=True,
+        text=True,
+    )  # nosec B603
+    assert (
+        result.stdout
+        == """
+The effective command line invocation was:
+subparsers.py \\
+    foo \\
+        --one eggs \\
+        --two spam \\
+        --three 42
+""".lstrip()
+    )
diff --git a/test/requirements.txt b/test/requirements.txt
index c92d67f..4585c8b 100644
--- a/test/requirements.txt
+++ b/test/requirements.txt
@@ -2,6 +2,7 @@
 
 bandit
 black
+dateparser
 flake8
 flake8-bugbear
 mypy