sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
22
lib/freetype/tests/README.md
Normal file
22
lib/freetype/tests/README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Unit and regression tests for the FreeType library
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Download test fonts
|
||||
|
||||
Run the `tests/scripts/download-fonts.py` script, which will
|
||||
download test fonts to the `tests/data/` directory first.
|
||||
|
||||
### Build the test programs
|
||||
|
||||
The tests are only built with the Meson build system, and
|
||||
are disabled by default, enable the 'tests' option to compile
|
||||
them, as in:
|
||||
|
||||
meson setup out -Dtests=enabled
|
||||
meson compile -C out
|
||||
|
||||
### Run the test programs
|
||||
|
||||
meson test -C out
|
||||
|
48
lib/freetype/tests/issue-1063/main.c
Normal file
48
lib/freetype/tests/issue-1063/main.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <freetype/freetype.h>
|
||||
#include <ft2build.h>
|
||||
|
||||
|
||||
int
|
||||
main( void )
|
||||
{
|
||||
FT_Library library;
|
||||
FT_Face face = NULL;
|
||||
|
||||
/*
|
||||
* We assume that `FREETYPE_TESTS_DATA_DIR` was set by `meson test`.
|
||||
* Otherwise we default to `../tests/data`.
|
||||
*
|
||||
* TODO (David): Rewrite this to pass the test directory through the
|
||||
* command-line.
|
||||
*/
|
||||
const char* testdata_dir = getenv( "FREETYPE_TESTS_DATA_DIR" );
|
||||
char filepath[FILENAME_MAX];
|
||||
|
||||
|
||||
snprintf( filepath, sizeof( filepath ), "%s/%s",
|
||||
testdata_dir ? testdata_dir : "../tests/data",
|
||||
"As.I.Lay.Dying.ttf" );
|
||||
|
||||
FT_Init_FreeType( &library );
|
||||
if ( FT_New_Face( library, filepath, 0, &face ) != 0 )
|
||||
{
|
||||
fprintf( stderr, "Could not open file: %s\n", filepath );
|
||||
return 1;
|
||||
}
|
||||
|
||||
for ( FT_ULong i = 59; i < 171; i++ )
|
||||
{
|
||||
FT_UInt gid = FT_Get_Char_Index( face, i );
|
||||
FT_Error code = FT_Load_Glyph( face, gid, FT_LOAD_DEFAULT );
|
||||
|
||||
|
||||
if ( code )
|
||||
printf( "unknown %d for char %lu, gid %u\n", code, i, gid );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
14
lib/freetype/tests/meson.build
Normal file
14
lib/freetype/tests/meson.build
Normal file
|
@ -0,0 +1,14 @@
|
|||
test_issue_1063 = executable('issue-1063',
|
||||
files([ 'issue-1063/main.c' ]),
|
||||
dependencies: freetype_dep,
|
||||
)
|
||||
|
||||
test_env = ['FREETYPE_TESTS_DATA_DIR='
|
||||
+ join_paths(meson.current_source_dir(), 'data')]
|
||||
|
||||
test('issue-1063',
|
||||
test_issue_1063,
|
||||
env: test_env,
|
||||
suite: 'regression')
|
||||
|
||||
# EOF
|
302
lib/freetype/tests/scripts/download-test-fonts.py
Normal file
302
lib/freetype/tests/scripts/download-test-fonts.py
Normal file
|
@ -0,0 +1,302 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""Download test fonts used by the FreeType regression test programs. These
|
||||
will be copied to $FREETYPE/tests/data/ by default."""
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
from typing import Callable, List, Optional, Tuple
|
||||
|
||||
# The list of download items describing the font files to install. Each
|
||||
# download item is a dictionary with one of the following schemas:
|
||||
#
|
||||
# - File item:
|
||||
#
|
||||
# file_url
|
||||
# Type: URL string.
|
||||
# Required: Yes.
|
||||
# Description: URL to download the file from.
|
||||
#
|
||||
# install_name
|
||||
# Type: file name string
|
||||
# Required: No
|
||||
# Description: Installation name for the font file, only provided if
|
||||
# it must be different from the original URL's basename.
|
||||
#
|
||||
# hex_digest
|
||||
# Type: hexadecimal string
|
||||
# Required: No
|
||||
# Description: Digest of the input font file.
|
||||
#
|
||||
# - Zip items:
|
||||
#
|
||||
# These items correspond to one or more font files that are embedded in a
|
||||
# remote zip archive. Each entry has the following fields:
|
||||
#
|
||||
# zip_url
|
||||
# Type: URL string.
|
||||
# Required: Yes.
|
||||
# Description: URL to download the zip archive from.
|
||||
#
|
||||
# zip_files
|
||||
# Type: List of file entries (see below)
|
||||
# Required: Yes
|
||||
# Description: A list of entries describing a single font file to be
|
||||
# extracted from the archive
|
||||
#
|
||||
# Apart from that, some schemas are used for dictionaries used inside
|
||||
# download items:
|
||||
#
|
||||
# - File entries:
|
||||
#
|
||||
# These are dictionaries describing a single font file to extract from an
|
||||
# archive.
|
||||
#
|
||||
# filename
|
||||
# Type: file path string
|
||||
# Required: Yes
|
||||
# Description: Path of source file, relative to the archive's
|
||||
# top-level directory.
|
||||
#
|
||||
# install_name
|
||||
# Type: file name string
|
||||
# Required: No
|
||||
# Description: Installation name for the font file; only provided if
|
||||
# it must be different from the original filename value.
|
||||
#
|
||||
# hex_digest
|
||||
# Type: hexadecimal string
|
||||
# Required: No
|
||||
# Description: Digest of the input source file
|
||||
#
|
||||
_DOWNLOAD_ITEMS = [
|
||||
{
|
||||
"zip_url": "https://github.com/python-pillow/Pillow/files/6622147/As.I.Lay.Dying.zip",
|
||||
"zip_files": [
|
||||
{
|
||||
"filename": "As I Lay Dying.ttf",
|
||||
"install_name": "As.I.Lay.Dying.ttf",
|
||||
"hex_digest": "ef146bbc2673b387",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def digest_data(data: bytes):
|
||||
"""Compute the digest of a given input byte string, which are the first
|
||||
8 bytes of its sha256 hash."""
|
||||
m = hashlib.sha256()
|
||||
m.update(data)
|
||||
return m.digest()[:8]
|
||||
|
||||
|
||||
def check_existing(path: str, hex_digest: str):
|
||||
"""Return True if |path| exists and matches |hex_digest|."""
|
||||
if not os.path.exists(path) or hex_digest is None:
|
||||
return False
|
||||
|
||||
with open(path, "rb") as f:
|
||||
existing_content = f.read()
|
||||
|
||||
return bytes.fromhex(hex_digest) == digest_data(existing_content)
|
||||
|
||||
|
||||
def install_file(content: bytes, dest_path: str):
|
||||
"""Write a byte string to a given destination file.
|
||||
|
||||
Args:
|
||||
content: Input data, as a byte string
|
||||
dest_path: Installation path
|
||||
"""
|
||||
parent_path = os.path.dirname(dest_path)
|
||||
if not os.path.exists(parent_path):
|
||||
os.makedirs(parent_path)
|
||||
|
||||
with open(dest_path, "wb") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def download_file(url: str, expected_digest: Optional[bytes] = None):
|
||||
"""Download a file from a given URL.
|
||||
|
||||
Args:
|
||||
url: Input URL
|
||||
expected_digest: Optional digest of the file
|
||||
as a byte string
|
||||
Returns:
|
||||
URL content as binary string.
|
||||
"""
|
||||
r = requests.get(url, allow_redirects=True)
|
||||
content = r.content
|
||||
if expected_digest is not None:
|
||||
digest = digest_data(r.content)
|
||||
if digest != expected_digest:
|
||||
raise ValueError(
|
||||
"%s has invalid digest %s (expected %s)"
|
||||
% (url, digest.hex(), expected_digest.hex())
|
||||
)
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def extract_file_from_zip_archive(
|
||||
archive: zipfile.ZipFile,
|
||||
archive_name: str,
|
||||
filepath: str,
|
||||
expected_digest: Optional[bytes] = None,
|
||||
):
|
||||
"""Extract a file from a given zipfile.ZipFile archive.
|
||||
|
||||
Args:
|
||||
archive: Input ZipFile objec.
|
||||
archive_name: Archive name or URL, only used to generate a
|
||||
human-readable error message.
|
||||
|
||||
filepath: Input filepath in archive.
|
||||
expected_digest: Optional digest for the file.
|
||||
Returns:
|
||||
A new File instance corresponding to the extract file.
|
||||
Raises:
|
||||
ValueError if expected_digest is not None and does not match the
|
||||
extracted file.
|
||||
"""
|
||||
file = archive.open(filepath)
|
||||
if expected_digest is not None:
|
||||
digest = digest_data(archive.open(filepath).read())
|
||||
if digest != expected_digest:
|
||||
raise ValueError(
|
||||
"%s in zip archive at %s has invalid digest %s (expected %s)"
|
||||
% (filepath, archive_name, digest.hex(), expected_digest.hex())
|
||||
)
|
||||
return file.read()
|
||||
|
||||
|
||||
def _get_and_install_file(
|
||||
install_path: str,
|
||||
hex_digest: Optional[str],
|
||||
force_download: bool,
|
||||
get_content: Callable[[], bytes],
|
||||
) -> bool:
|
||||
if not force_download and hex_digest is not None \
|
||||
and os.path.exists(install_path):
|
||||
with open(install_path, "rb") as f:
|
||||
content: bytes = f.read()
|
||||
if bytes.fromhex(hex_digest) == digest_data(content):
|
||||
return False
|
||||
|
||||
content = get_content()
|
||||
install_file(content, install_path)
|
||||
return True
|
||||
|
||||
|
||||
def download_and_install_item(
|
||||
item: dict, install_dir: str, force_download: bool
|
||||
) -> List[Tuple[str, bool]]:
|
||||
"""Download and install one item.
|
||||
|
||||
Args:
|
||||
item: Download item as a dictionary, see above for schema.
|
||||
install_dir: Installation directory.
|
||||
force_download: Set to True to force download and installation, even
|
||||
if the font file is already installed with the right content.
|
||||
|
||||
Returns:
|
||||
A list of (install_name, status) tuples, where 'install_name' is the
|
||||
file's installation name under 'install_dir', and 'status' is a
|
||||
boolean that is True to indicate that the file was downloaded and
|
||||
installed, or False to indicate that the file is already installed
|
||||
with the right content.
|
||||
"""
|
||||
if "file_url" in item:
|
||||
file_url = item["file_url"]
|
||||
install_name = item.get("install_name", os.path.basename(file_url))
|
||||
install_path = os.path.join(install_dir, install_name)
|
||||
hex_digest = item.get("hex_digest")
|
||||
|
||||
def get_content():
|
||||
return download_file(file_url, hex_digest)
|
||||
|
||||
status = _get_and_install_file(
|
||||
install_path, hex_digest, force_download, get_content
|
||||
)
|
||||
return [(install_name, status)]
|
||||
|
||||
if "zip_url" in item:
|
||||
# One or more files from a zip archive.
|
||||
archive_url = item["zip_url"]
|
||||
archive = zipfile.ZipFile(io.BytesIO(download_file(archive_url)))
|
||||
|
||||
result = []
|
||||
for f in item["zip_files"]:
|
||||
filename = f["filename"]
|
||||
install_name = f.get("install_name", filename)
|
||||
hex_digest = f.get("hex_digest")
|
||||
|
||||
def get_content():
|
||||
return extract_file_from_zip_archive(
|
||||
archive,
|
||||
archive_url,
|
||||
filename,
|
||||
bytes.fromhex(hex_digest) if hex_digest else None,
|
||||
)
|
||||
|
||||
status = _get_and_install_file(
|
||||
os.path.join(install_dir, install_name),
|
||||
hex_digest,
|
||||
force_download,
|
||||
get_content,
|
||||
)
|
||||
result.append((install_name, status))
|
||||
|
||||
return result
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown download item schema: %s" % item)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
|
||||
# Assume this script is under tests/scripts/ and tests/data/
|
||||
# is the default installation directory.
|
||||
install_dir = os.path.normpath(
|
||||
os.path.join(os.path.dirname(__file__), "..", "data")
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Force download and installation of font files",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--install-dir",
|
||||
default=install_dir,
|
||||
help="Specify installation directory [%s]" % install_dir,
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
for item in _DOWNLOAD_ITEMS:
|
||||
for install_name, status in download_and_install_item(
|
||||
item, args.install_dir, args.force
|
||||
):
|
||||
print("%s %s" % (install_name,
|
||||
"INSTALLED" if status else "UP-TO-DATE"))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
# EOF
|
Loading…
Add table
Add a link
Reference in a new issue