From b10c7c699b49b1701692c0d0edc7691ac71c3c8f Mon Sep 17 00:00:00 2001 From: Ryan de Kleer Date: Thu, 15 Sep 2022 16:51:34 -0700 Subject: [PATCH 1/2] Fix false-positive in content gen. test failures Assert equal dirs by return value of diff subprocess, rather than its output. This prevents tests from failing when file contents are the same but the file modes are different. Fix #3042 --- pelican/tests/support.py | 17 ++++++++++++ pelican/tests/test_pelican.py | 51 +++++++++++++++++------------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/pelican/tests/support.py b/pelican/tests/support.py index 55ddf625..8a394395 100644 --- a/pelican/tests/support.py +++ b/pelican/tests/support.py @@ -218,6 +218,23 @@ class LogCountHandler(BufferingHandler): ]) +def diff_subproc(first, second): + """ + Return a subprocess that runs a diff on the two paths. + + Check results with:: + + >>> out_stream, err_stream = proc.communicate() + >>> didCheckFail = proc.returnCode != 0 + """ + return subprocess.Popen( + ['git', '--no-pager', 'diff', '--no-ext-diff', '--exit-code', + '-w', first, second], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + + class LoggedTestCase(unittest.TestCase): """A test case that captures log messages.""" diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py index 389dbb3d..adba32e0 100644 --- a/pelican/tests/test_pelican.py +++ b/pelican/tests/test_pelican.py @@ -3,6 +3,7 @@ import logging import os import subprocess import sys +import unittest from collections.abc import Sequence from shutil import rmtree from tempfile import mkdtemp @@ -10,8 +11,12 @@ from tempfile import mkdtemp from pelican import Pelican from pelican.generators import StaticGenerator from pelican.settings import read_settings -from pelican.tests.support import (LoggedTestCase, locale_available, - mute, unittest) +from pelican.tests.support import ( + LoggedTestCase, + diff_subproc, + locale_available, + mute +) CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) SAMPLES_PATH = os.path.abspath(os.path.join( @@ -54,28 +59,19 @@ class TestPelican(LoggedTestCase): locale.setlocale(locale.LC_ALL, self.old_locale) super().tearDown() - def assertDirsEqual(self, left_path, right_path): - out, err = subprocess.Popen( - ['git', '--no-pager', 'diff', '--no-ext-diff', '--exit-code', - '-w', left_path, right_path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ).communicate() + def assertDirsEqual(self, left_path, right_path, msg=None): + """ + Check if the files are the same (ignoring whitespace) below both paths. + """ + proc = diff_subproc(left_path, right_path) - def ignorable_git_crlf_errors(line): - # Work around for running tests on Windows - for msg in [ - "LF will be replaced by CRLF", - "CRLF will be replaced by LF", - "The file will have its original line endings"]: - if msg in line: - return True - return False - if err: - err = '\n'.join([line for line in err.decode('utf8').splitlines() - if not ignorable_git_crlf_errors(line)]) - assert not out, out - assert not err, err + out, err = proc.communicate() + if proc.returncode != 0: + msg = self._formatMessage( + msg, + "%s and %s differ:\n%s" % (left_path, right_path, err) + ) + raise self.failureException(msg) def test_order_of_generators(self): # StaticGenerator must run last, so it can identify files that @@ -104,7 +100,8 @@ class TestPelican(LoggedTestCase): pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( - self.temp_path, os.path.join(OUTPUT_PATH, 'basic')) + self.temp_path, os.path.join(OUTPUT_PATH, 'basic') + ) self.assertLogCountEqual( count=1, msg="Unable to find.*skipping url replacement", @@ -121,7 +118,8 @@ class TestPelican(LoggedTestCase): pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( - self.temp_path, os.path.join(OUTPUT_PATH, 'custom')) + self.temp_path, os.path.join(OUTPUT_PATH, 'custom') + ) @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') @@ -141,7 +139,8 @@ class TestPelican(LoggedTestCase): pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( - self.temp_path, os.path.join(OUTPUT_PATH, 'custom_locale')) + self.temp_path, os.path.join(OUTPUT_PATH, 'custom_locale') + ) def test_theme_static_paths_copy(self): # the same thing with a specified set of settings should work From b6a9a8333b285e9781d290187c69b5667f428579 Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Sat, 28 Oct 2023 14:49:55 +0300 Subject: [PATCH 2/2] skip tests that require git if git is not installed and minor tweaks to subprocess handling --- pelican/tests/support.py | 3 ++- pelican/tests/test_pelican.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pelican/tests/support.py b/pelican/tests/support.py index 8a394395..720e4d0e 100644 --- a/pelican/tests/support.py +++ b/pelican/tests/support.py @@ -231,7 +231,8 @@ def diff_subproc(first, second): ['git', '--no-pager', 'diff', '--no-ext-diff', '--exit-code', '-w', first, second], stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + text=True, ) diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py index adba32e0..885c2138 100644 --- a/pelican/tests/test_pelican.py +++ b/pelican/tests/test_pelican.py @@ -15,7 +15,8 @@ from pelican.tests.support import ( LoggedTestCase, diff_subproc, locale_available, - mute + mute, + skipIfNoExecutable, ) CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -69,7 +70,8 @@ class TestPelican(LoggedTestCase): if proc.returncode != 0: msg = self._formatMessage( msg, - "%s and %s differ:\n%s" % (left_path, right_path, err) + "%s and %s differ:\nstdout:\n%s\nstderr\n%s" % + (left_path, right_path, out, err) ) raise self.failureException(msg) @@ -88,6 +90,7 @@ class TestPelican(LoggedTestCase): generator_classes, Sequence, "_get_generator_classes() must return a Sequence to preserve order") + @skipIfNoExecutable(['git', '--version']) def test_basic_generation_works(self): # when running pelican without settings, it should pick up the default # ones and generate correct output without raising any exception @@ -107,6 +110,7 @@ class TestPelican(LoggedTestCase): msg="Unable to find.*skipping url replacement", level=logging.WARNING) + @skipIfNoExecutable(['git', '--version']) def test_custom_generation_works(self): # the same thing with a specified set of settings should work settings = read_settings(path=SAMPLE_CONFIG, override={ @@ -121,6 +125,7 @@ class TestPelican(LoggedTestCase): self.temp_path, os.path.join(OUTPUT_PATH, 'custom') ) + @skipIfNoExecutable(['git', '--version']) @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') def test_custom_locale_generation_works(self):