-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9797f3c
commit e422c14
Showing
14 changed files
with
633 additions
and
710 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from fontTools.ttLib import TTFont | ||
|
||
from conftest import check_id | ||
from fontbakery.status import FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
from fontbakery.utils import remove_cmap_entry | ||
|
||
|
||
@check_id("case_mapping") | ||
def test_check_case_mapping(check): | ||
"""Ensure the font supports case swapping for all its glyphs.""" | ||
|
||
ttFont = TTFont(TEST_FILE("merriweather/Merriweather-Regular.ttf")) | ||
# Glyph present in the font Missing case-swapping counterpart | ||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
# U+01D3: LATIN CAPITAL LETTER U WITH CARON U+01D4: LATIN SMALL LETTER U WITH CARON | ||
# U+01E6: LATIN CAPITAL LETTER G WITH CARON U+01E7: LATIN SMALL LETTER G WITH CARON | ||
# U+01F4: LATIN CAPITAL LETTER G WITH ACUTE U+01F5: LATIN SMALL LETTER G WITH ACUTE | ||
assert_results_contain(check(ttFont), FAIL, "missing-case-counterparts") | ||
|
||
# While we'd expect designers to draw the missing counterparts, | ||
# for testing purposes we can simply delete the glyphs that lack a counterpart | ||
# to make the check PASS: | ||
remove_cmap_entry(ttFont, 0x01D3) | ||
remove_cmap_entry(ttFont, 0x01E6) | ||
remove_cmap_entry(ttFont, 0x01F4) | ||
assert_PASS(check(ttFont)) | ||
|
||
# Let's add something which *does* have case swapping but which isn't a letter | ||
# to ensure the check doesn't fail for such glyphs. | ||
for table in ttFont["cmap"].tables: | ||
table.cmap[0x2160] = "uni2160" # ROMAN NUMERAL ONE, which downcases to 0x2170 | ||
assert 0x2170 not in ttFont.getBestCmap() | ||
assert_PASS(check(ttFont)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from unittest.mock import patch, MagicMock | ||
|
||
import pytest | ||
import requests | ||
|
||
from conftest import check_id | ||
from fontbakery.status import FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
from fontbakery.checks.fontbakery import is_up_to_date | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"installed, latest, result", | ||
[ | ||
# True when installed >= latest | ||
("0.5.0", "0.5.0", True), | ||
("0.5.1", "0.5.0", True), | ||
("0.5.1", "0.5.0.post2", True), | ||
("2.0.0", "1.5.1", True), | ||
("0.8.10", "0.8.9", True), | ||
("0.5.2.dev73+g8c9ebc0.d20181023", "0.5.1", True), | ||
("0.8.10.dev1+g666b3425", "0.8.9", True), | ||
("0.8.10.dev2+gfa9260bf", "0.8.9.post2", True), | ||
("0.8.10a9", "0.8.9", True), | ||
("0.8.10rc1.dev3+g494879af.d20220825", "0.8.9", True), | ||
# False when installed < latest | ||
("0.4.1", "0.5.0", False), | ||
("0.3.4", "0.3.5", False), | ||
("1.0.0", "1.0.1", False), | ||
("0.8.9", "0.8.10", False), | ||
("0.5.0", "0.5.0.post2", False), | ||
("0.8.9.dev1+g666b3425", "0.8.9.post2", False), | ||
("0.5.2.dev73+g8c9ebc0.d20181023", "0.5.2", False), | ||
("0.5.2.dev73+g8c9ebc0.d20181023", "0.5.3", False), | ||
("0.8.10rc0", "0.8.10", False), | ||
("0.8.10rc0", "0.8.10.post", False), | ||
("0.8.10rc1.dev3+g494879af.d20220825", "0.8.10", False), | ||
("0.8.10rc1.dev3+g494879af.d20220825", "0.8.10.post", False), | ||
], | ||
) | ||
def test_is_up_to_date(installed, latest, result): | ||
assert is_up_to_date(installed, latest) is result | ||
|
||
|
||
class MockDistribution: | ||
"""Helper class to mock pip-api's Distribution class.""" | ||
|
||
def __init__(self, version: str): | ||
self.name = "fontbakery" | ||
self.version = version | ||
|
||
def __repr__(self): | ||
return f"<Distribution(name='{self.name}', version='{self.version}')>" | ||
|
||
|
||
# We don't want to make an actual GET request to PyPI.org, so we'll mock it. | ||
# We'll also mock pip-api's 'installed_distributions' method. | ||
@patch("pip_api.installed_distributions") | ||
@patch("requests.get") | ||
def test_check_fontbakery_version(mock_get, mock_installed): | ||
"""Check if FontBakery is up-to-date""" | ||
from fontbakery.codetesting import CheckTester | ||
|
||
check = CheckTester("fontbakery_version") | ||
|
||
# Any of the test fonts can be used here. | ||
# The check requires a 'font' argument but it doesn't do anything with it. | ||
font = TEST_FILE("nunito/Nunito-Regular.ttf") | ||
|
||
mock_response = MagicMock() | ||
mock_response.status_code = 200 | ||
|
||
# Test the case of installed version being the same as PyPI's version. | ||
latest_ver = installed_ver = "0.1.0" | ||
mock_response.json.return_value = {"info": {"version": latest_ver}} | ||
mock_get.return_value = mock_response | ||
mock_installed.return_value = {"fontbakery": MockDistribution(installed_ver)} | ||
assert_PASS(check(font)) | ||
|
||
# Test the case of installed version being newer than PyPI's version. | ||
installed_ver = "0.1.1" | ||
mock_installed.return_value = {"fontbakery": MockDistribution(installed_ver)} | ||
assert_PASS(check(font)) | ||
|
||
# Test the case of installed version being older than PyPI's version. | ||
installed_ver = "0.0.1" | ||
mock_installed.return_value = {"fontbakery": MockDistribution(installed_ver)} | ||
msg = assert_results_contain(check(font), FAIL, "outdated-fontbakery") | ||
assert ( | ||
f"Current FontBakery version is {installed_ver}," | ||
f" while a newer {latest_ver} is already available." | ||
) in msg | ||
|
||
# Test the case of an unsuccessful response to the GET request. | ||
mock_response.status_code = 500 | ||
mock_response.content = "500 Internal Server Error" | ||
msg = assert_results_contain(check(font), FAIL, "unsuccessful-request-500") | ||
assert "Request to PyPI.org was not successful" in msg | ||
|
||
# Test the case of the GET request failing due to a connection error. | ||
mock_get.side_effect = requests.exceptions.ConnectionError | ||
msg = assert_results_contain(check(font), FAIL, "connection-error") | ||
assert "Request to PyPI.org failed with this message" in msg | ||
|
||
|
||
@pytest.mark.xfail(reason="Often happens until rebasing") | ||
@check_id("fontbakery_version") | ||
def test_check_fontbakery_version_live_apis(check): | ||
"""Check if FontBakery is up-to-date. (No API-mocking edition)""" | ||
|
||
# Any of the test fonts can be used here. | ||
# The check requires a 'font' argument but it doesn't do anything with it. | ||
font = TEST_FILE("nunito/Nunito-Regular.ttf") | ||
|
||
# The check will make an actual request to PyPI.org, | ||
# and will query 'pip' to determine which version of 'fontbakery' is installed. | ||
# The check should PASS. | ||
assert_PASS(check(font)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from fontTools.ttLib import TTFont | ||
|
||
from conftest import check_id | ||
from fontbakery.status import WARN, FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
|
||
|
||
@check_id("mandatory_glyphs") | ||
def test_check_mandatory_glyphs(check): | ||
"""Font contains the first few mandatory glyphs (.null or NULL, CR and space)?""" | ||
from fontTools import subset | ||
|
||
ttFont = TTFont(TEST_FILE("nunito/Nunito-Regular.ttf")) | ||
assert_PASS(check(ttFont)) | ||
|
||
options = subset.Options() | ||
options.glyph_names = True # Preserve glyph names | ||
# By default, the subsetter keeps the '.notdef' glyph but removes its outlines | ||
subsetter = subset.Subsetter(options) | ||
subsetter.populate(text="mn") # Arbitrarily remove everything except 'm' and 'n' | ||
subsetter.subset(ttFont) | ||
message = assert_results_contain(check(ttFont), FAIL, "notdef-is-blank") | ||
assert message == "The '.notdef' glyph should contain a drawing, but it is blank." | ||
|
||
options.notdef_glyph = False # Drop '.notdef' glyph | ||
subsetter = subset.Subsetter(options) | ||
subsetter.populate(text="mn") | ||
subsetter.subset(ttFont) | ||
message = assert_results_contain(check(ttFont), WARN, "notdef-not-found") | ||
assert message == "Font should contain the '.notdef' glyph." | ||
|
||
# Change the glyph name from 'n' to '.notdef' | ||
# (Must reload the font here since we already decompiled the glyf table) | ||
ttFont = TTFont(TEST_FILE("nunito/Nunito-Regular.ttf")) | ||
ttFont.glyphOrder = ["m", ".notdef"] | ||
for subtable in ttFont["cmap"].tables: | ||
if subtable.isUnicode(): | ||
subtable.cmap[110] = ".notdef" | ||
if 0 in subtable.cmap: | ||
del subtable.cmap[0] | ||
results = check(ttFont) | ||
message = assert_results_contain([results[0]], WARN, "notdef-not-first") | ||
assert message == "The '.notdef' should be the font's first glyph." | ||
|
||
message = assert_results_contain([results[1]], WARN, "notdef-has-codepoint") | ||
assert message == ( | ||
"The '.notdef' glyph should not have a Unicode codepoint value assigned," | ||
" but has 0x006E." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from fontTools.ttLib import TTFont | ||
|
||
from conftest import check_id | ||
from fontbakery.status import FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
|
||
|
||
@check_id("name/trailing_spaces") | ||
def test_check_name_trailing_spaces(check): | ||
"""Name table entries must not have trailing spaces.""" | ||
|
||
# Our reference Cabin Regular is known to be good: | ||
ttFont = TTFont(TEST_FILE("cabin/Cabin-Regular.ttf")) | ||
assert_PASS(check(ttFont), "with a good font...") | ||
|
||
for i, entry in enumerate(ttFont["name"].names): | ||
good_string = ttFont["name"].names[i].toUnicode() | ||
bad_string = good_string + " " | ||
ttFont["name"].names[i].string = bad_string.encode(entry.getEncoding()) | ||
assert_results_contain( | ||
check(ttFont), | ||
FAIL, | ||
"trailing-space", | ||
f'with a bad name table entry ({i}: "{bad_string}")...', | ||
) | ||
|
||
# restore good entry before moving to the next one: | ||
ttFont["name"].names[i].string = good_string.encode(entry.getEncoding()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from conftest import check_id | ||
from fontbakery.status import WARN, FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
|
||
|
||
@check_id("ots") | ||
def test_check_ots(check): | ||
"""Checking with ots-sanitize.""" | ||
|
||
fine_font = TEST_FILE("cabin/Cabin-Regular.ttf") | ||
assert_PASS(check(fine_font)) | ||
|
||
warn_font = TEST_FILE("bad_fonts/ots/bad_post_version.otf") | ||
message = assert_results_contain(check(warn_font), WARN, "ots-sanitize-warn") | ||
assert ( | ||
"WARNING: post: Only version supported for fonts with CFF table is" | ||
" 0x00030000 not 0x20000" in message | ||
) | ||
|
||
bad_font = TEST_FILE("bad_fonts/ots/no_glyph_data.ttf") | ||
message = assert_results_contain(check(bad_font), FAIL, "ots-sanitize-error") | ||
assert "ERROR: no supported glyph data table(s) present" in message | ||
assert "Failed to sanitize file!" in message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from fontTools.ttLib import TTFont | ||
|
||
from conftest import check_id | ||
from fontbakery.status import SKIP, FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
|
||
|
||
@check_id("rupee") | ||
def test_check_rupee(check): | ||
"""Ensure indic fonts have the Indian Rupee Sign glyph.""" | ||
|
||
ttFont = TTFont(TEST_FILE("mada/Mada-Regular.ttf")) | ||
msg = assert_results_contain(check(ttFont), SKIP, "unfulfilled-conditions") | ||
assert "Unfulfilled Conditions: is_indic_font" in msg | ||
|
||
# This one is good: | ||
ttFont = TTFont( | ||
TEST_FILE("indic-font-with-rupee-sign/NotoSerifDevanagari-Regular.ttf") | ||
) | ||
assert_PASS(check(ttFont)) | ||
|
||
# But this one lacks the glyph: | ||
ttFont = TTFont( | ||
TEST_FILE("indic-font-without-rupee-sign/NotoSansOlChiki-Regular.ttf") | ||
) | ||
msg = assert_results_contain(check(ttFont), FAIL, "missing-rupee") | ||
assert msg == "Please add a glyph for Indian Rupee Sign (₹) at codepoint U+20B9." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from fontTools.ttLib import TTFont | ||
import pytest | ||
|
||
from conftest import check_id | ||
from fontbakery.status import WARN | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
assert_results_contain, | ||
TEST_FILE, | ||
) | ||
from fontbakery.utils import remove_cmap_entry | ||
|
||
|
||
@pytest.fixture | ||
def montserrat_ttFonts(): | ||
paths = [ | ||
TEST_FILE("montserrat/Montserrat-Black.ttf"), | ||
TEST_FILE("montserrat/Montserrat-BlackItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Bold.ttf"), | ||
TEST_FILE("montserrat/Montserrat-BoldItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-ExtraBold.ttf"), | ||
TEST_FILE("montserrat/Montserrat-ExtraBoldItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-ExtraLight.ttf"), | ||
TEST_FILE("montserrat/Montserrat-ExtraLightItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Italic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Light.ttf"), | ||
TEST_FILE("montserrat/Montserrat-LightItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Medium.ttf"), | ||
TEST_FILE("montserrat/Montserrat-MediumItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Regular.ttf"), | ||
TEST_FILE("montserrat/Montserrat-SemiBold.ttf"), | ||
TEST_FILE("montserrat/Montserrat-SemiBoldItalic.ttf"), | ||
TEST_FILE("montserrat/Montserrat-Thin.ttf"), | ||
TEST_FILE("montserrat/Montserrat-ThinItalic.ttf"), | ||
] | ||
return [TTFont(path) for path in paths] | ||
|
||
|
||
@check_id("soft_hyphen") | ||
def test_check_soft_hyphen(check, montserrat_ttFonts): | ||
"""Check glyphs contain the recommended contour count""" | ||
for ttFont in montserrat_ttFonts: | ||
# Montserrat has a softhyphen... | ||
assert_results_contain(check(ttFont), WARN, "softhyphen") | ||
|
||
remove_cmap_entry(ttFont, 0x00AD) | ||
assert_PASS(check(ttFont)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from conftest import check_id | ||
|
||
# from fontbakery.status import FAIL | ||
from fontbakery.codetesting import ( | ||
assert_PASS, | ||
# assert_results_contain, | ||
TEST_FILE, | ||
) | ||
|
||
|
||
@check_id("ttx_roundtrip") | ||
def test_check_ttx_roundtrip(check): | ||
"""Checking with fontTools.ttx""" | ||
|
||
font = TEST_FILE("mada/Mada-Regular.ttf") | ||
assert_PASS(check(font)) | ||
|
||
# TODO: Can anyone show us a font file that fails ttx roundtripping?! | ||
# | ||
# font = TEST_FILE("...") | ||
# assert_results_contain(check(font), | ||
# FAIL, None) # FIXME: This needs a message keyword |
Oops, something went wrong.