|
| 1 | +import os |
| 2 | + |
| 3 | +import pytest |
| 4 | + |
| 5 | +from pyhttpd.conf import HttpdConf |
| 6 | + |
| 7 | +# A substitution may legitimately produce zero bytes. Later rules must still |
| 8 | +# see the (now empty) line and continue to work on the following lines. |
| 9 | +MODES = { |
| 10 | + 'regex_default': '', |
| 11 | + 'regex_flatten': 'f', |
| 12 | + 'regex_quick': 'q', |
| 13 | +} |
| 14 | + |
| 15 | +DOC = "## remove this completely\nfoo\n" |
| 16 | + |
| 17 | + |
| 18 | +class TestSubstituteEmptyResult: |
| 19 | + |
| 20 | + @pytest.fixture(autouse=True, scope='class') |
| 21 | + def _class_scope(self, env): |
| 22 | + doc_dir = os.path.join(env.server_dir, "htdocs", "test1") |
| 23 | + # Binary, so that no CRLF conversion happens on Windows. |
| 24 | + with open(os.path.join(doc_dir, "doc.html"), "wb") as f: |
| 25 | + f.write(DOC.encode()) |
| 26 | + |
| 27 | + def configure(self, env, rules): |
| 28 | + conf = HttpdConf(env, extras={ |
| 29 | + f"test1.{env.http_tld}": f""" |
| 30 | + <Location "/"> |
| 31 | + AddOutputFilterByType SUBSTITUTE text/html |
| 32 | + {rules} |
| 33 | + </Location> |
| 34 | + """, |
| 35 | + }) |
| 36 | + conf.add_vhost_test1() |
| 37 | + conf.install() |
| 38 | + assert env.apache_restart() == 0 |
| 39 | + |
| 40 | + def get(self, env, path): |
| 41 | + return env.curl_get(env.mkurl("http", "test1", path)) |
| 42 | + |
| 43 | + # A rule that empties a whole line, followed by another rule. |
| 44 | + @pytest.mark.parametrize("mode", list(MODES), ids=list(MODES)) |
| 45 | + def test_filters_004_01(self, env, mode): |
| 46 | + flags = MODES[mode] |
| 47 | + self.configure(env, f""" |
| 48 | + Substitute "s/^##.*//{flags}" |
| 49 | + Substitute "s/foo/bar/{flags}" |
| 50 | + """) |
| 51 | + r = self.get(env, "/doc.html") |
| 52 | + assert r.response, f"{mode}: no response" |
| 53 | + assert r.response["status"] == 200 |
| 54 | + assert r.response["body"].decode() == "\nbar\n" |
| 55 | + |
| 56 | + # The same with a literal (non-regex) pattern. |
| 57 | + @pytest.mark.parametrize("flags", ["nf", "nq"], ids=["literal_flatten", "literal_quick"]) |
| 58 | + def test_filters_004_05(self, env, flags): |
| 59 | + self.configure(env, f""" |
| 60 | + Substitute "s/## remove this completely//{flags}" |
| 61 | + Substitute "s/foo/bar/{flags}" |
| 62 | + """) |
| 63 | + r = self.get(env, "/doc.html") |
| 64 | + assert r.response, f"{flags}: no response" |
| 65 | + assert r.response["status"] == 200 |
| 66 | + assert r.response["body"].decode() == "\nbar\n" |
| 67 | + |
| 68 | + # Control: the emptying rule on its own. |
| 69 | + def test_filters_004_02(self, env): |
| 70 | + self.configure(env, 'Substitute "s/^##.*//"') |
| 71 | + r = self.get(env, "/doc.html") |
| 72 | + assert r.response, "no response" |
| 73 | + assert r.response["body"].decode() == "\nfoo\n" |
| 74 | + |
| 75 | + # Control: the first rule does not match, the second one does. |
| 76 | + def test_filters_004_03(self, env): |
| 77 | + self.configure(env, """ |
| 78 | + Substitute "s/^nomatch.*//" |
| 79 | + Substitute "s/foo/bar/" |
| 80 | + """) |
| 81 | + r = self.get(env, "/doc.html") |
| 82 | + assert r.response, "no response" |
| 83 | + assert r.response["body"].decode() == "## remove this completely\nbar\n" |
| 84 | + |
| 85 | + # Control: the first rule replaces the line with something non-empty. |
| 86 | + def test_filters_004_04(self, env): |
| 87 | + self.configure(env, """ |
| 88 | + Substitute "s/^##.*/xx/" |
| 89 | + Substitute "s/foo/bar/" |
| 90 | + """) |
| 91 | + r = self.get(env, "/doc.html") |
| 92 | + assert r.response, "no response" |
| 93 | + assert r.response["body"].decode() == "xx\nbar\n" |
0 commit comments