From bb047c04e7e0877b1f6a771876def096e24b8bc2 Mon Sep 17 00:00:00 2001 From: Isaiah Odhner Date: Tue, 12 Sep 2023 21:54:19 -0400 Subject: [PATCH] Move --recode-samples to an automated test --- CHANGELOG.md | 4 ++++ README.md | 19 +------------------ src/textual_paint/args.py | 2 +- src/textual_paint/paint.py | 36 ------------------------------------ tests/test_encoding.py | 31 +++++++++++++++++++++++++++++++ 5 files changed, 37 insertions(+), 55 deletions(-) create mode 100644 tests/test_encoding.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d3a96..6bedc11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed + +- `--recode-samples` option is removed, now covered by the `pytest` test suite. + ### Changed - Made radio buttons rounder in `--ascii-only` mode, using parentheses instead of square brackets. diff --git a/README.md b/README.md index d2be03f..4f0ae4d 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,6 @@ development options: --clear-screen Clear the screen before starting, to avoid seeing outdated errors --restart-on-changes Restart the app when the source code is changed - --recode-samples Open and save each file in samples/, for testing ``` ### Keyboard Shortcuts @@ -329,22 +328,6 @@ This also makes it run slower. Often it's useful to exclude events with `textual console -x EVENT`. -
-Testing file save/load roundtrip - -> There are at this point lots of files that will change if you run this, so don't worry about it. Some are generated files, so they naturally change somewhat. The `0x0.ans` file saves as 1x1, due to the minimum size. `pathological_character_grid.svg` was free-handed with Inkscape, so naturally changes somewhat when re-saving. There may be actual problems, but they're hard to spot in the noise. - -To test file encoding, run `textual run --dev "src.textual_paint.paint --recode-samples"`. - -If there are differences in the ANSI files, you can set up a special diff like this: -```bash -git config --local "diff.cat-show-all.textconv" "cat --show-all" -``` -but you should check that `cat --show-all samples/2x2.ans` works on your system first. -Also, note that it might not work with your Git GUI of choice; you may need to use the command line. - -
- ### Troubleshooting > `Unable to import 'app' from module 'src.textual_paint.paint'` @@ -373,7 +356,7 @@ PYRIGHT_PYTHON_FORCE_VERSION=1.1.318 pyright # I also tried mypy and fixed some errors it reported, but I'm not targeting zero errors with mypy. mypy src --no-namespace-packages --check-untyped-defs -# Visual Regression Testing +# Visual Regression Testing (and a few other tests) # I use pytest-textual-snapshot, which is a pytest plugin for comparing SVG screenshots of Textual apps over time. pytest # To accept differences, update the baseline with: diff --git a/src/textual_paint/args.py b/src/textual_paint/args.py index d48e128..1287eef 100644 --- a/src/textual_paint/args.py +++ b/src/textual_paint/args.py @@ -18,6 +18,7 @@ parser.add_argument('--ascii-only', action='store_true', help='Use only ASCII ch parser.add_argument('--backup-folder', default=None, metavar="FOLDER", help='Folder to save backups to. By default a backup is saved alongside the edited file.') # TODO: hide development options from help? there's quite a few of them now +# (...actually, less of them now, and I've grouped them together) dev_options = parser.add_argument_group('development options') dev_options.add_argument('--inspect-layout', action='store_true', help='Enables DOM inspector (F12) and middle click highlight') # This flag is important for my sanity during development, @@ -27,7 +28,6 @@ dev_options.add_argument('--inspect-layout', action='store_true', help='Enables # I really don't want false ones mixed in. You want to reward your brain for finding good solutions, after all. dev_options.add_argument('--clear-screen', action='store_true', help='Clear the screen before starting, to avoid seeing outdated errors') dev_options.add_argument('--restart-on-changes', action='store_true', help='Restart the app when the source code is changed') -dev_options.add_argument('--recode-samples', action='store_true', help='Open and save each file in samples/, for testing') parser.add_argument('filename', nargs='?', default=None, help='Path to a file to open. File will be created if it doesn\'t exist.') diff --git a/src/textual_paint/paint.py b/src/textual_paint/paint.py index f959c40..6d12183 100755 --- a/src/textual_paint/paint.py +++ b/src/textual_paint/paint.py @@ -4131,42 +4131,6 @@ else: # This requires the canvas to exist, hence call_later(). app.call_later(app.recover_from_backup) -if args.recode_samples: - # Re-encode the sample files to test for changes/inconsistency in encoding. - - async def recode_sample(file_path: str|Path) -> None: - """Re-encodes a single sample file.""" - print(f"Re-encoding {file_path}") - with open(file_path, "rb") as f: - image = AnsiArtDocument.decode_based_on_file_extension(f.read(), str(file_path)) - with open(file_path, "wb") as f: - f.write(image.encode_based_on_file_extension(str(file_path))) - print(f"Saved {file_path}") - - async def recode_samples() -> None: - """Re-encodes all sample files in parallel.""" - samples_folder = os.path.join(os.path.dirname(__file__), "../../samples") - tasks: list[Coroutine[Any, Any, None]] = [] - for file_path in Path(samples_folder).glob("**/*"): - # Skip backup files in case some sample file is being edited. - if file_path.name.endswith("~"): - continue - # Skip GIMP Palette files. - if file_path.name.endswith(".gpl"): - continue - # Skip folders. - if file_path.is_dir(): - continue - tasks.append(recode_sample(file_path)) - - await asyncio.gather(*tasks) - - # have to wait for the app to be initialized - async def once_running() -> None: - await recode_samples() - app.exit() - app.call_later(once_running) - if args.clear_screen: os.system("cls||clear") diff --git a/tests/test_encoding.py b/tests/test_encoding.py new file mode 100644 index 0000000..3cd0031 --- /dev/null +++ b/tests/test_encoding.py @@ -0,0 +1,31 @@ +"""Test that files are encoded correctly.""" + +from pathlib import Path +import pytest + +from textual_paint.ansi_art_document import AnsiArtDocument + +ROUND_TRIP_EXCLUSIONS = [ + # These files are generated by a script, not the Textual Paint app, so they naturally change. + "4x4_font_template.ans", + "gradient_test.ans", + # This one was free-handed with Inkscape, so naturally changes a lot. + "pathological_character_grid.svg", + # The `0x0.ans` file saves as 1x1, due to the minimum size. + "0x0.ans", + # This is a color palette file, meant to be loaded with Get Colors, not Open. + "pipe_strip_palette.gpl", + # THIS ONE MAYBE SHOULD IDEALLY WORK? But I need a better way of viewing a diff... + "cp437_as_utf8.txt", +] +SAMPLES_DIR = Path(__file__).parent.parent / "samples" +SAMPLES = [f for f in SAMPLES_DIR.iterdir() if f.is_file() and "~" not in f.name] +ROUND_TRIP_SAMPLES = [f for f in SAMPLES if f.name not in ROUND_TRIP_EXCLUSIONS] + +@pytest.mark.parametrize("file_path", ROUND_TRIP_SAMPLES) +def test_round_trip(file_path: Path) -> None: + """Test that files are re-encoded identically when opened and saved.""" + with open(file_path, "rb") as f: + file_content = f.read() + image = AnsiArtDocument.decode_based_on_file_extension(file_content, str(file_path)) + assert image.encode_based_on_file_extension(str(file_path)) == file_content