| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this |
| # file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| |
| import os |
| import subprocess |
| import tempfile |
| |
| REPO = "https://github.com/abarth/http-state.git" |
| TEST_FILE = "cookie_http_state.rs" |
| DOMAIN = "http://home.example.org:8888" |
| RUST_FN = """ |
| #[test]{should_panic} |
| fn test_{name}() {{ |
| let r = run("{set_location}", |
| {set_cookies}, |
| "{location}"); |
| assert_eq!(&r, "{expect}"); |
| }} |
| """ |
| SET_COOKIES_INDENT = 18 |
| SHOULD_PANIC = "\n#[should_panic] // Look at cookie_http_state_utils.py if this test fails" |
| |
| # Those tests should PASS. But until fixes land in servo, keep them failing |
| FAILING_TESTS = [ |
| "0003", # Waiting for a way to clean expired cookies |
| "0006", # Waiting for a way to clean expired cookies |
| "mozilla0001", # Waiting for a way to clean expired cookies |
| "mozilla0002", # Waiting for a way to clean expired cookies |
| "mozilla0003", # Waiting for a way to clean expired cookies |
| "mozilla0005", # Waiting for a way to clean expired cookies |
| "mozilla0007", # Waiting for a way to clean expired cookies |
| "mozilla0009", # Waiting for a way to clean expired cookies |
| "mozilla0010", # Waiting for a way to clean expired cookies |
| "mozilla0013", # Waiting for a way to clean expired cookies |
| ] |
| |
| |
| def list_tests(dir): |
| suffix = "-test" |
| |
| def keep(name): |
| return name.endswith(suffix) and not name.startswith("disabled") |
| |
| tests = [name[:-len(suffix)] for name in os.listdir(dir) if keep(name)] |
| tests.sort() |
| return tests |
| |
| |
| def escape(s): |
| """ Escape the string `s` so that it can be parsed by rust as a valid |
| UTF-8 string. |
| We can't use only `encode("unicode_escape")` as it produces things that |
| rust does not accept ("\\xbf", "\\u6265" for example). So we manually |
| convert all character whose code point is greater than 128 to |
| \\u{code_point}. |
| All other characters are encoded with "unicode_escape" to get escape |
| sequences ("\\r" for example) except for `"` that we specifically escape |
| because our string will be quoted by double-quotes. |
| Lines are also limited in size, so split the string every 70 characters |
| (gives room for indentation). |
| """ |
| res = "" |
| last_split = 0 |
| for c in s: |
| if len(res) - last_split > 70: |
| res += "\\\n" |
| last_split = len(res) |
| o = ord(c) |
| if o == 34: |
| res += "\\\"" |
| continue |
| if o >= 128: |
| res += "\\u{" + hex(o)[2:] + "}" |
| else: |
| res += c.encode("unicode_escape") |
| return res |
| |
| |
| def format_slice_cookies(cookies): |
| esc_cookies = ['"%s"' % escape(c) for c in cookies] |
| if sum(len(s) for s in esc_cookies) < 80: |
| sep = ", " |
| else: |
| sep = ",\n" + " " * SET_COOKIES_INDENT |
| return "&[" + sep.join(esc_cookies) + "]" |
| |
| |
| def generate_code_for_test(test_dir, name): |
| if name in FAILING_TESTS: |
| should_panic = SHOULD_PANIC |
| else: |
| should_panic = "" |
| |
| test_file = os.path.join(test_dir, name + "-test") |
| expect_file = os.path.join(test_dir, name + "-expected") |
| |
| set_cookies = [] |
| set_location = DOMAIN + "/cookie-parser?" + name |
| expect = "" |
| location = DOMAIN + "/cookie-parser-result?" + name |
| |
| with open(test_file) as fo: |
| for line in fo: |
| line = line.decode("utf-8").rstrip() |
| prefix = "Set-Cookie: " |
| if line.startswith(prefix): |
| set_cookies.append(line[len(prefix):]) |
| prefix = "Location: " |
| if line.startswith(prefix): |
| location = line[len(prefix):] |
| if location.startswith("/"): |
| location = DOMAIN + location |
| |
| with open(expect_file) as fo: |
| for line in fo: |
| line = line.decode("utf-8").rstrip() |
| prefix = "Cookie: " |
| if line.startswith(prefix): |
| expect = line[len(prefix):] |
| |
| return RUST_FN.format(name=name.replace('-', '_'), |
| set_location=escape(set_location), |
| set_cookies=format_slice_cookies(set_cookies), |
| should_panic=should_panic, |
| location=escape(location), |
| expect=escape(expect)) |
| |
| |
| def update_test_file(cachedir): |
| workdir = os.path.dirname(os.path.realpath(__file__)) |
| test_file = os.path.join(workdir, TEST_FILE) |
| |
| # Create the cache dir |
| if not os.path.isdir(cachedir): |
| os.makedirs(cachedir) |
| |
| # Clone or update the repo |
| repo_dir = os.path.join(cachedir, "http-state") |
| if os.path.isdir(repo_dir): |
| args = ["git", "pull", "-f"] |
| process = subprocess.Popen(args, cwd=repo_dir) |
| if process.wait() != 0: |
| print("failed to update the http-state git repo") |
| return 1 |
| else: |
| args = ["git", "clone", REPO, repo_dir] |
| process = subprocess.Popen(args) |
| if process.wait() != 0: |
| print("failed to clone the http-state git repo") |
| return 1 |
| |
| # Truncate the unit test file to remove all existing tests |
| with open(test_file, "r+") as fo: |
| while True: |
| line = fo.readline() |
| if line.strip() == "// Test listing": |
| fo.truncate() |
| fo.flush() |
| break |
| if line == "": |
| print("Failed to find listing delimiter on unit test file") |
| return 1 |
| |
| # Append all tests to unit test file |
| tests_dir = os.path.join(repo_dir, "tests", "data", "parser") |
| with open(test_file, "a") as fo: |
| for test in list_tests(tests_dir): |
| fo.write(generate_code_for_test(tests_dir, test).encode("utf-8")) |
| |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| update_test_file(tempfile.gettempdir()) |