diff options
Diffstat (limited to '')
-rw-r--r-- | tests/contrast/min_contrasts.json | 50 | ||||
-rw-r--r-- | tests/contrast/test_contrasts.py | 101 |
2 files changed, 151 insertions, 0 deletions
diff --git a/tests/contrast/min_contrasts.json b/tests/contrast/min_contrasts.json new file mode 100644 index 0000000..a69d73f --- /dev/null +++ b/tests/contrast/min_contrasts.json @@ -0,0 +1,50 @@ +{ + "default": 4.5, + "emacs": 2.4, + "friendly": 2.2, + "friendly_grayscale": 2.2, + "colorful": 2.2, + "autumn": 2.2, + "murphy": 1.4, + "manni": 1.4, + "material": 1.6, + "monokai": 2.3, + "perldoc": 2.7, + "pastie": 2.5, + "borland": 2.3, + "trac": 2.3, + "native": 3.0, + "fruity": 1.6, + "bw": 21.0, + "vim": 1.3, + "vs": 3.6, + "tango": 2.4, + "rrt": 5.3, + "xcode": 5.1, + "igor": 3.6, + "paraiso-light": 1.3, + "paraiso-dark": 1.3, + "lovelace": 3.5, + "algol": 3.5, + "algol_nu": 3.5, + "arduino": 2.6, + "rainbow_dash": 2.1, + "abap": 2.5, + "solarized-dark": 1.5, + "solarized-light": 1.0, + "sas": 4.6, + "staroffice": 4.5, + "stata": 2.4, + "stata-light": 2.4, + "stata-dark": 3.4, + "inkpot": 1.0, + "zenburn": 1.6, + "gruvbox-dark": 4.0, + "gruvbox-light": 3.2, + "dracula": 1.4, + "one-dark": 3.7, + "lilypond": 2.3, + "nord": 2.4, + "nord-darker": 2.8, + "github-dark": 4.8 +}
\ No newline at end of file diff --git a/tests/contrast/test_contrasts.py b/tests/contrast/test_contrasts.py new file mode 100644 index 0000000..517b34e --- /dev/null +++ b/tests/contrast/test_contrasts.py @@ -0,0 +1,101 @@ +""" + Contrast Tests + ~~~~~~~~~~ + + Pygments styles should be accessible to people with suboptimal vision. + This test ensures that the minimum contrast of styles does not degrade, + and that every rule of a new style fulfills the WCAG AA standard.[1] + + [1]: https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html +""" + +import json +import os +import sys + +import pygments.styles +import pygments.token +import wcag_contrast_ratio + +JSON_FILENAME = os.path.join(os.path.dirname(__file__), "min_contrasts.json") +WCAG_AA_CONTRAST = 4.5 + + +def hex2rgb(hexstr): + hexstr = hexstr.lstrip("#") + r = int(hexstr[:2], 16) / 255 + g = int(hexstr[2:4], 16) / 255 + b = int(hexstr[4:], 16) / 255 + return (r, g, b) + + +def get_style_contrasts(style_cls): + return [ + ( + round( + wcag_contrast_ratio.rgb( + hex2rgb(style["bgcolor"] or style_cls.background_color), + hex2rgb(style["color"] or "#000000") + # we default to black because browsers also do + ), + 1, + ), + ttype, + ) + for ttype, style in style_cls.list_styles() + if ttype != pygments.token.Whitespace + ] + + +def builtin_styles(): + for style_name in pygments.styles.STYLE_MAP: + yield (style_name, pygments.styles.get_style_by_name(style_name)) + + +def min_contrasts(): + return { + name: min(x[0] for x in get_style_contrasts(style)) + for name, style in builtin_styles() + } + + +def update_json(): + with open(JSON_FILENAME, "w") as f: + json.dump( + min_contrasts(), + f, + indent=2, + ) + + +def test_contrasts(fail_if_improved=True): + with open(JSON_FILENAME) as f: + previous_contrasts = json.load(f) + + for style_name in pygments.styles.STYLE_MAP: + style = pygments.styles.get_style_by_name(style_name) + contrasts = get_style_contrasts(style) + min_contrast = min([x[0] for x in contrasts]) + + bar = previous_contrasts.get(style_name, WCAG_AA_CONTRAST) + + assert not min_contrast < bar, ( + "contrast degradation for style '{}'\n" + "The following rules have a contrast lower than the required {}:\n\n" + "{}\n" + ).format( + style_name, + bar, + "\n".join( + [ + "* {:.2f} {}".format(contrast, ttype) + for contrast, ttype in contrasts + if contrast < bar + ] + ), + ) + + if fail_if_improved: + assert ( + not min_contrast > bar + ), "congrats, you improved a contrast! please run ./scripts/update_contrasts.py" |