Revision 93dd7360
Added by koszko almost 2 years ago
common/patterns.js | ||
---|---|---|
7 | 7 |
* Redistribution terms are gathered in the `copyright' file. |
8 | 8 |
*/ |
9 | 9 |
|
10 |
const MAX_URL_PATH_LEN = 12; |
|
11 |
const MAX_URL_PATH_CHARS = 255; |
|
12 |
const MAX_DOMAIN_LEN = 7; |
|
13 |
const MAX_DOMAIN_CHARS = 100; |
|
10 |
const MAX = { |
|
11 |
URL_PATH_LEN: 12, |
|
12 |
URL_PATH_CHARS: 255, |
|
13 |
DOMAIN_LEN: 7, |
|
14 |
DOMAIN_CHARS: 100 |
|
15 |
}; |
|
14 | 16 |
|
15 | 17 |
const proto_regex = /^(\w+):\/\/(.*)$/; |
16 | 18 |
|
17 | 19 |
const user_re = "[^/?#@]+@" |
18 |
const domain_re = "[^/?#]+";
|
|
20 |
const domain_re = "[.a-zA-Z0-9-]+";
|
|
19 | 21 |
const path_re = "[^?#]*"; |
20 | 22 |
const query_re = "\\??[^#]*"; |
21 | 23 |
|
... | ... | |
25 | 27 |
|
26 | 28 |
const ftp_regex = new RegExp(`^(${user_re})?(${domain_re})(${path_re}).*`); |
27 | 29 |
|
28 |
function deconstruct_url(url) |
|
30 |
function deconstruct_url(url, use_limits=true)
|
|
29 | 31 |
{ |
32 |
const max = MAX; |
|
33 |
if (!use_limits) { |
|
34 |
for (key in MAX) |
|
35 |
max[key] = Infinity; |
|
36 |
} |
|
37 |
|
|
30 | 38 |
const proto_match = proto_regex.exec(url); |
31 | 39 |
if (proto_match === null) |
32 |
return undefined;
|
|
40 |
throw `bad url '${url}'`;
|
|
33 | 41 |
|
34 | 42 |
const deco = {proto: proto_match[1]}; |
35 | 43 |
|
... | ... | |
37 | 45 |
deco.path = file_regex.exec(proto_match[2])[1]; |
38 | 46 |
} else if (deco.proto === "ftp") { |
39 | 47 |
[deco.domain, deco.path] = ftp_regex.exec(proto_match[2]).slice(2, 4); |
40 |
} else { |
|
48 |
} else if (deco.proto === "http" || deco.proto === "https") {
|
|
41 | 49 |
const http_match = http_regex.exec(proto_match[2]); |
42 | 50 |
if (!http_match) |
43 | 51 |
return undefined; |
44 | 52 |
[deco.domain, deco.path, deco.query] = http_match.slice(1, 4); |
53 |
deco.domain = deco.domain.toLowerCase(); |
|
54 |
} else { |
|
55 |
throw `unsupported protocol in url '${url}'`; |
|
45 | 56 |
} |
46 | 57 |
|
47 |
const leading_dash = deco.path[0] === "/"; |
|
48 | 58 |
deco.trailing_dash = deco.path[deco.path.length - 1] === "/"; |
49 | 59 |
|
50 | 60 |
if (deco.domain) { |
51 |
if (deco.domain.length > MAX_DOMAIN_CHARS) {
|
|
61 |
if (deco.domain.length > max.DOMAIN_CHARS) {
|
|
52 | 62 |
const idx = deco.domain.indexOf(".", deco.domain.length - |
53 |
MAX_DOMAIN_CHARS);
|
|
63 |
max.DOMAIN_CHARS);
|
|
54 | 64 |
if (idx === -1) |
55 | 65 |
deco.domain = []; |
56 | 66 |
else |
... | ... | |
59 | 69 |
deco.domain_truncated = true; |
60 | 70 |
} |
61 | 71 |
|
62 |
if (deco.path.length > MAX_URL_PATH_CHARS) {
|
|
72 |
if (deco.path.length > max.URL_PATH_CHARS) {
|
|
63 | 73 |
deco.path = deco.path.substring(0, deco.path.lastIndexOf("/")); |
64 | 74 |
deco.path_truncated = true; |
65 | 75 |
} |
... | ... | |
67 | 77 |
|
68 | 78 |
if (typeof deco.domain === "string") { |
69 | 79 |
deco.domain = deco.domain.split("."); |
70 |
if (deco.domain.splice(0, deco.domain.length - MAX_DOMAIN_LEN).length
|
|
80 |
if (deco.domain.splice(0, deco.domain.length - max.DOMAIN_LEN).length
|
|
71 | 81 |
> 0) |
72 | 82 |
deco.domain_truncated = true; |
73 | 83 |
} |
74 | 84 |
|
75 | 85 |
deco.path = deco.path.split("/").filter(s => s !== ""); |
76 |
if (deco.domain && deco.path.splice(MAX_URL_PATH_LEN).length > 0)
|
|
86 |
if (deco.domain && deco.path.splice(max.URL_PATH_LEN).length > 0)
|
|
77 | 87 |
deco.path_truncated = true; |
78 |
if (leading_dash || deco.path.length === 0) |
|
79 |
deco.path.unshift(""); |
|
80 | 88 |
|
81 | 89 |
return deco; |
82 | 90 |
} |
... | ... | |
98 | 106 |
|
99 | 107 |
function* each_path_pattern(deco) |
100 | 108 |
{ |
101 |
for (let slice = deco.path.length; slice > 0; slice--) { |
|
102 |
const path_part = deco.path.slice(0, slice).join("/");
|
|
109 |
for (let slice = deco.path.length; slice >= 0; slice--) {
|
|
110 |
const path_part = ["", ...deco.path.slice(0, slice)].join("/");
|
|
103 | 111 |
const path_wildcards = []; |
104 | 112 |
if (slice === deco.path.length && !deco.path_truncated) { |
105 | 113 |
if (deco.trailing_dash) |
106 | 114 |
yield path_part + "/"; |
107 |
yield path_part; |
|
115 |
if (slice > 0 || deco.proto !== "file") |
|
116 |
yield path_part; |
|
108 | 117 |
} |
109 | 118 |
if (slice === deco.path.length - 1 && !deco.path_truncated && |
110 | 119 |
deco.path[slice] !== "*") |
... | ... | |
137 | 146 |
/* |
138 | 147 |
* EXPORTS_START |
139 | 148 |
* EXPORT each_url_pattern |
149 |
* EXPORT deconstruct_url |
|
140 | 150 |
* EXPORTS_END |
141 | 151 |
*/ |
compute_scripts.awk | ||
---|---|---|
105 | 105 |
} |
106 | 106 |
} |
107 | 107 |
|
108 |
function wrap_file(filename) { |
|
109 |
print "\"use strict\";\n\n({fun: (function() {\n" |
|
108 |
function partially_wrap_file(filename) { |
|
110 | 109 |
print_imports_code(filename) |
111 | 110 |
printf "\n\n" |
112 | 111 |
|
... | ... | |
114 | 113 |
|
115 | 114 |
printf "\n\n" |
116 | 115 |
print_exports_code(filename) |
116 |
} |
|
117 |
|
|
118 |
function wrap_file(filename) { |
|
119 |
print "\"use strict\";\n\n({fun: (function() {\n" |
|
120 |
|
|
121 |
partially_wrap_file(filename) |
|
122 |
|
|
117 | 123 |
print "\n})}).fun();" |
118 | 124 |
} |
119 | 125 |
|
... | ... | |
151 | 157 |
} |
152 | 158 |
|
153 | 159 |
function print_usage() { |
154 |
printf "usage: %2 compute_scripts.awk script_dependencies|wrapped_code FILENAME[...]\n", |
|
160 |
printf "usage: %2 compute_scripts.awk script_dependencies|wrapped_code|partially_wrapped_code FILENAME[...]\n",
|
|
155 | 161 |
ARGV[0] > "/dev/stderr" |
156 | 162 |
exit 1 |
157 | 163 |
} |
... | ... | |
189 | 195 |
print("exports_init.js") |
190 | 196 |
if (compute_dependencies(root_filename) > 0) |
191 | 197 |
exit 1 |
198 |
} else if (operation == "partially_wrapped_code") { |
|
199 |
partially_wrap_file(root_filename) |
|
192 | 200 |
} else if (operation == "wrapped_code") { |
193 | 201 |
wrap_file(root_filename) |
194 | 202 |
} else { |
copyright | ||
---|---|---|
75 | 75 |
Comment: Wojtek Kosior promises not to sue even in case of violations |
76 | 76 |
of the license. |
77 | 77 |
|
78 |
Files: test/__init__.py test/test_unit.py test/default_profiles/icecat_empty/extensions.json |
|
78 |
Files: test/__init__.py test/unit/* |
|
79 |
test/default_profiles/icecat_empty/extensions.json |
|
79 | 80 |
Copyright: 2021 Wojtek Kosior <koszko@koszko.org> |
80 | 81 |
License: CC0 |
81 | 82 |
|
82 |
Files: test/profiles.py test/script_loader.py |
|
83 |
Files: test/profiles.py test/script_loader.py test/unit/conftest.py
|
|
83 | 84 |
Copyright: 2021 Wojtek Kosior <koszko@koszko.org> |
84 | 85 |
License: GPL-3+ |
85 | 86 |
Comment: Wojtek Kosior promises not to sue even in case of violations |
test/__init__.py | ||
---|---|---|
1 | 1 |
# SPDX-License-Identifier: CC0-1.0 |
2 |
# Copyright (C) 2021 Wojtek Kosior |
test/profiles.py | ||
---|---|---|
43 | 43 |
profile.set_preference(f'network.proxy.backup.{proto}', '') |
44 | 44 |
profile.set_preference(f'network.proxy.backup.{proto}_port', 0) |
45 | 45 |
|
46 |
def set_profile_console_logging(profile): |
|
47 |
profile.set_preference('devtools.console.stdout.content', True) |
|
48 |
|
|
46 | 49 |
def firefox_safe_mode(firefox_binary=default_firefox_binary, |
47 | 50 |
proxy_host=default_proxy_host, |
48 | 51 |
proxy_port=default_proxy_port): |
49 | 52 |
profile = webdriver.FirefoxProfile() |
50 | 53 |
set_profile_proxy(profile, proxy_host, proxy_port) |
54 |
set_profile_console_logging(profile) |
|
51 | 55 |
|
52 | 56 |
options = Options() |
53 | 57 |
options.add_argument('--safe-mode') |
... | ... | |
61 | 65 |
proxy_port=default_proxy_port): |
62 | 66 |
profile = webdriver.FirefoxProfile(profile_dir) |
63 | 67 |
set_profile_proxy(profile, proxy_host, proxy_port) |
68 |
set_profile_console_logging(profile) |
|
64 | 69 |
|
65 | 70 |
return webdriver.Firefox(firefox_profile=profile, |
66 | 71 |
firefox_binary=firefox_binary) |
test/script_loader.py | ||
---|---|---|
49 | 49 |
if script_name_regex.match(script.name): |
50 | 50 |
yield script |
51 | 51 |
|
52 |
def get_wrapped_script(script_path):
|
|
52 |
def wrapped_script(script_path, wrap_partially=True):
|
|
53 | 53 |
if script_path == 'exports_init.js': |
54 | 54 |
with open(script_root / 'MOZILLA_exports_init.js') as script: |
55 | 55 |
return script.read() |
56 | 56 |
|
57 |
awk = subprocess.run(['awk', '-f', str(awk_script), 'wrapped_code', |
|
58 |
str(script_path)], |
|
59 |
stdout=subprocess.PIPE, cwd=script_root, check=True) |
|
57 |
command = 'partially_wrapped_code' if wrap_partially else 'wrapped_code' |
|
58 |
awk_command = ['awk', '-f', str(awk_script), command, str(script_path)] |
|
59 |
awk = subprocess.run(awk_command, stdout=subprocess.PIPE, cwd=script_root, |
|
60 |
check=True) |
|
60 | 61 |
|
61 | 62 |
return awk.stdout.decode() |
62 | 63 |
|
... | ... | |
67 | 68 |
project directory. |
68 | 69 |
|
69 | 70 |
Return a string containing script from `path` together with all other |
70 |
scripts it depends on, wrapped in the same way Haketilo's build system wraps |
|
71 |
them, with imports properly satisfied. |
|
71 |
scripts it depends. Dependencies are wrapped in the same way Haketilo's |
|
72 |
build system wraps them, with imports properly satisfied. The main script |
|
73 |
being loaded is wrapped partially - it also has its imports satisfied, but |
|
74 |
its code is not placed inside an anonymous function, so the |
|
72 | 75 |
""" |
73 | 76 |
path = make_relative_path(path) |
74 | 77 |
|
... | ... | |
79 | 82 |
str(path), *[str(s) for s in available]], |
80 | 83 |
stdout=subprocess.PIPE, cwd=script_root, check=True) |
81 | 84 |
|
82 |
output = awk.stdout.decode() |
|
85 |
to_load = awk.stdout.decode().split() |
|
86 |
texts = [wrapped_script(path, wrap_partially=(i == len(to_load) - 1)) |
|
87 |
for i, path in enumerate(to_load)] |
|
83 | 88 |
|
84 |
return '\n'.join([get_wrapped_script(path) for path in output.split()]) |
|
89 |
return '\n'.join(texts) |
test/test_unit.py | ||
---|---|---|
1 |
# SPDX-License-Identifier: CC0-1.0 |
|
2 |
|
|
3 |
""" |
|
4 |
Haketilo unit tests |
|
5 |
""" |
|
6 |
|
|
7 |
# This file is part of Haketilo |
|
8 |
# |
|
9 |
# Copyright (C) 2021, jahoti |
|
10 |
# Copyright (C) 2021, Wojtek Kosior |
|
11 |
# |
|
12 |
# This program is free software: you can redistribute it and/or modify |
|
13 |
# it under the terms of the CC0 1.0 Universal License as published by |
|
14 |
# the Creative Commons Corporation. |
|
15 |
# |
|
16 |
# This program is distributed in the hope that it will be useful, |
|
17 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19 |
# CC0 1.0 Universal License for more details. |
|
20 |
|
|
21 |
import pytest |
|
22 |
from .profiles import firefox_safe_mode |
|
23 |
from .server import do_an_internet |
|
24 |
from .script_loader import load_script |
|
25 |
|
|
26 |
@pytest.fixture(scope="module") |
|
27 |
def proxy(): |
|
28 |
httpd = do_an_internet() |
|
29 |
yield httpd |
|
30 |
httpd.shutdown() |
|
31 |
|
|
32 |
@pytest.fixture(scope="module") |
|
33 |
def driver(proxy): |
|
34 |
with firefox_safe_mode() as driver: |
|
35 |
yield driver |
|
36 |
driver.quit() |
|
37 |
|
|
38 |
def test_proxy(driver): |
|
39 |
""" |
|
40 |
A trivial test case that verifies mocked web pages served by proxy can be |
|
41 |
accessed by the browser driven. |
|
42 |
""" |
|
43 |
for proto in ['http://', 'https://']: |
|
44 |
driver.get(proto + 'gotmyowndoma.in') |
|
45 |
element = driver.find_element_by_tag_name('title') |
|
46 |
title = driver.execute_script('return arguments[0].innerText;', element) |
|
47 |
assert "Schrodinger's Document" in title |
|
48 |
|
|
49 |
def test_script_loader(driver): |
|
50 |
""" |
|
51 |
A trivial test case that verifies Haketilo's .js files can be properly |
|
52 |
loaded into a test page together with their dependencies. |
|
53 |
""" |
|
54 |
driver.get('http://gotmyowndoma.in') |
|
55 |
driver.execute_script(load_script('common/stored_types.js', ['common'])) |
|
56 |
get_var_prefix = 'return window.haketilo_exports.TYPE_PREFIX.VAR;' |
|
57 |
assert driver.execute_script(get_var_prefix) == '_' |
test/unit/__init__.py | ||
---|---|---|
1 |
# SPDX-License-Identifier: CC0-1.0 |
|
2 |
# Copyright (C) 2021 Wojtek Kosior |
test/unit/conftest.py | ||
---|---|---|
1 |
# SPDX-License-Identifier: GPL-3.0-or-later |
|
2 |
|
|
3 |
""" |
|
4 |
Common fixtures for Haketilo unit tests |
|
5 |
""" |
|
6 |
|
|
7 |
# This file is part of Haketilo. |
|
8 |
# |
|
9 |
# Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org> |
|
10 |
# |
|
11 |
# This program is free software: you can redistribute it and/or modify |
|
12 |
# it under the terms of the GNU General Public License as published by |
|
13 |
# the Free Software Foundation, either version 3 of the License, or |
|
14 |
# (at your option) any later version. |
|
15 |
# |
|
16 |
# This program is distributed in the hope that it will be useful, |
|
17 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19 |
# GNU General Public License for more details. |
|
20 |
# |
|
21 |
# You should have received a copy of the GNU General Public License |
|
22 |
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|
23 |
# |
|
24 |
# I, Wojtek Kosior, thereby promise not to sue for violation of this file's |
|
25 |
# license. Although I request that you do not make use this code in a |
|
26 |
# proprietary program, I am not going to enforce this in court. |
|
27 |
|
|
28 |
import pytest |
|
29 |
|
|
30 |
from ..profiles import firefox_safe_mode |
|
31 |
from ..server import do_an_internet |
|
32 |
from ..script_loader import load_script |
|
33 |
|
|
34 |
@pytest.fixture(scope="package") |
|
35 |
def proxy(): |
|
36 |
httpd = do_an_internet() |
|
37 |
yield httpd |
|
38 |
httpd.shutdown() |
|
39 |
|
|
40 |
@pytest.fixture(scope="package") |
|
41 |
def driver(proxy): |
|
42 |
with firefox_safe_mode() as driver: |
|
43 |
yield driver |
|
44 |
driver.quit() |
|
45 |
|
|
46 |
script_injecting_script = '''\ |
|
47 |
/* |
|
48 |
* Selenium by default executes scripts in some weird one-time context. We want |
|
49 |
* separately-loaded scripts to be able to access global variables defined |
|
50 |
* before, including those declared with `const` or `let`. To achieve that, we |
|
51 |
* run our scripts by injecting them into the page inside a <script> tag. We use |
|
52 |
* custom properties of the `window` object to communicate with injected code. |
|
53 |
*/ |
|
54 |
|
|
55 |
const script_elem = document.createElement('script'); |
|
56 |
script_elem.textContent = arguments[0]; |
|
57 |
|
|
58 |
delete window.haketilo_selenium_return_value; |
|
59 |
delete window.haketilo_selenium_exception; |
|
60 |
window.returnval = (val => window.haketilo_selenium_return_value = val); |
|
61 |
window.arguments = arguments[1]; |
|
62 |
|
|
63 |
document.body.append(script_elem); |
|
64 |
|
|
65 |
/* |
|
66 |
* To ease debugging, we want this script to forward signal all exceptions from |
|
67 |
* the injectee. |
|
68 |
*/ |
|
69 |
try { |
|
70 |
if (window.haketilo_selenium_exception !== false) |
|
71 |
throw 'Error in injected script! Check your geckodriver.log!'; |
|
72 |
} finally { |
|
73 |
script_elem.remove(); |
|
74 |
} |
|
75 |
|
|
76 |
return window.haketilo_selenium_return_value; |
|
77 |
''' |
|
78 |
|
|
79 |
def _execute_in_page_context(driver, script, *args): |
|
80 |
script = script + '\n;\nwindow.haketilo_selenium_exception = false;' |
|
81 |
try: |
|
82 |
return driver.execute_script(script_injecting_script, script, args) |
|
83 |
except Exception as e: |
|
84 |
import sys |
|
85 |
lines = enumerate(script.split('\n'), 1) |
|
86 |
for err_info in [('Failing script\n',), *lines]: |
|
87 |
print(*err_info, file=sys.stderr) |
|
88 |
|
|
89 |
raise e from None |
|
90 |
|
|
91 |
@pytest.fixture(scope="package") |
|
92 |
def execute_in_page(driver): |
|
93 |
def do_execute(script, *args, **kwargs): |
|
94 |
if 'page' in kwargs: |
|
95 |
driver.get(kwargs['page']) |
|
96 |
|
|
97 |
return _execute_in_page_context(driver, script, args) |
|
98 |
|
|
99 |
yield do_execute |
|
100 |
|
|
101 |
@pytest.fixture(scope="package") |
|
102 |
def load_into_page(driver): |
|
103 |
def do_load(path, import_dirs, *args, **kwargs): |
|
104 |
if 'page' in kwargs: |
|
105 |
driver.get(kwargs['page']) |
|
106 |
|
|
107 |
_execute_in_page_context(driver, load_script(path, import_dirs), args) |
|
108 |
|
|
109 |
yield do_load |
test/unit/test_basic.py | ||
---|---|---|
1 |
# SPDX-License-Identifier: CC0-1.0 |
|
2 |
|
|
3 |
""" |
|
4 |
Haketilo unit tests - base |
|
5 |
""" |
|
6 |
|
|
7 |
# This file is part of Haketilo |
|
8 |
# |
|
9 |
# Copyright (C) 2021, Wojtek Kosior |
|
10 |
# |
|
11 |
# This program is free software: you can redistribute it and/or modify |
|
12 |
# it under the terms of the CC0 1.0 Universal License as published by |
|
13 |
# the Creative Commons Corporation. |
|
14 |
# |
|
15 |
# This program is distributed in the hope that it will be useful, |
|
16 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
18 |
# CC0 1.0 Universal License for more details. |
|
19 |
|
|
20 |
import pytest |
|
21 |
|
|
22 |
def test_driver(driver): |
|
23 |
""" |
|
24 |
A trivial test case that verifies mocked web pages served by proxy can be |
|
25 |
accessed by the browser driven. |
|
26 |
""" |
|
27 |
for proto in ['http://', 'https://']: |
|
28 |
driver.get(proto + 'gotmyowndoma.in') |
|
29 |
element = driver.find_element_by_tag_name('title') |
|
30 |
title = driver.execute_script('return arguments[0].innerText;', element) |
|
31 |
assert "Schrodinger's Document" in title |
|
32 |
|
|
33 |
def test_script_loader(execute_in_page, load_into_page): |
|
34 |
""" |
|
35 |
A trivial test case that verifies Haketilo's .js files can be properly |
|
36 |
loaded into a test page together with their dependencies. |
|
37 |
""" |
|
38 |
load_into_page('common/stored_types.js', ['common'], |
|
39 |
page='https://gotmyowndoma.in') |
|
40 |
|
|
41 |
assert execute_in_page('returnval(TYPE_PREFIX.VAR);') == '_' |
test/unit/test_patterns.py | ||
---|---|---|
1 |
# SPDX-License-Identifier: CC0-1.0 |
|
2 |
|
|
3 |
""" |
|
4 |
Haketilo unit tests - URL patterns |
|
5 |
""" |
|
6 |
|
|
7 |
# This file is part of Haketilo |
|
8 |
# |
|
9 |
# Copyright (C) 2021, Wojtek Kosior |
|
10 |
# |
|
11 |
# This program is free software: you can redistribute it and/or modify |
|
12 |
# it under the terms of the CC0 1.0 Universal License as published by |
|
13 |
# the Creative Commons Corporation. |
|
14 |
# |
|
15 |
# This program is distributed in the hope that it will be useful, |
|
16 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
18 |
# CC0 1.0 Universal License for more details. |
|
19 |
|
|
20 |
import pytest |
|
21 |
|
|
22 |
from ..script_loader import load_script |
|
23 |
|
|
24 |
@pytest.fixture(scope="session") |
|
25 |
def patterns_code(): |
|
26 |
yield load_script('common/patterns.js', ['common']) |
|
27 |
|
|
28 |
def test_regexes(execute_in_page, patterns_code): |
|
29 |
""" |
|
30 |
patterns.js contains regexes used for URL parsing. |
|
31 |
Verify they work properly. |
|
32 |
""" |
|
33 |
execute_in_page(patterns_code, page='https://gotmyowndoma.in') |
|
34 |
|
|
35 |
valid_url = 'https://example.com/a/b?ver=1.2.3#heading2' |
|
36 |
valid_url_rest = 'example.com/a/b?ver=1.2.3#heading2' |
|
37 |
|
|
38 |
# Test matching of URL protocol. |
|
39 |
match = execute_in_page('returnval(proto_regex.exec(arguments[0]));', |
|
40 |
valid_url) |
|
41 |
assert match |
|
42 |
assert match[1] == 'https' |
|
43 |
assert match[2] == valid_url_rest |
|
44 |
|
|
45 |
match = execute_in_page('returnval(proto_regex.exec(arguments[0]));', |
|
46 |
'://bad-url.missing/protocol') |
|
47 |
assert match is None |
|
48 |
|
|
49 |
# Test matching of http(s) URLs. |
|
50 |
match = execute_in_page('returnval(http_regex.exec(arguments[0]));', |
|
51 |
valid_url_rest) |
|
52 |
assert match |
|
53 |
assert match[1] == 'example.com' |
|
54 |
assert match[2] == '/a/b' |
|
55 |
assert match[3] == '?ver=1.2.3' |
|
56 |
|
|
57 |
match = execute_in_page('returnval(http_regex.exec(arguments[0]));', |
|
58 |
'another.example.com') |
|
59 |
assert match |
|
60 |
assert match[1] == 'another.example.com' |
|
61 |
assert match[2] == '' |
|
62 |
assert match[3] == '' |
|
63 |
|
|
64 |
match = execute_in_page('returnval(http_regex.exec(arguments[0]));', |
|
65 |
'/bad/http/example') |
|
66 |
assert match == None |
|
67 |
|
|
68 |
# Test matching of file URLs. |
|
69 |
match = execute_in_page('returnval(file_regex.exec(arguments[0]));', |
|
70 |
'/good/file/example') |
|
71 |
assert match |
|
72 |
assert match[1] == '/good/file/example' |
|
73 |
|
|
74 |
# Test matching of ftp URLs. |
|
75 |
match = execute_in_page('returnval(ftp_regex.exec(arguments[0]));', |
|
76 |
'example.com/a/b#heading2') |
|
77 |
assert match |
|
78 |
assert match[1] is None |
|
79 |
assert match[2] == 'example.com' |
|
80 |
assert match[3] == '/a/b' |
|
81 |
|
|
82 |
match = execute_in_page('returnval(ftp_regex.exec(arguments[0]));', |
|
83 |
'some_user@localhost') |
|
84 |
assert match |
|
85 |
assert match[1] == 'some_user@' |
|
86 |
assert match[2] == 'localhost' |
|
87 |
assert match[3] == '' |
|
88 |
|
|
89 |
match = execute_in_page('returnval(ftp_regex.exec(arguments[0]));', |
|
90 |
'@bad.url/') |
|
91 |
assert match is None |
Also available in: Unified diff
improve unit testing approach
Unit tests were moved to their own subdirectory.
Fixtures common to many unit tests were moved to test/unit/conftest.py.
A facility to execute scripts in page's global scope was added.
A workaround was employed to present information about errors in injected scripts.
Sample unit tests for regexes in common/patterns.js were added.