1#!/usr/bin/env python 2 3# 4# Copyright (C) 2024 The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import json 20import sys 21import unittest 22 23from font_builder import parse_font_from_json_for_sanitization_test, parse_fonts_from_json_for_validation_test 24 25 26class FontBuilderTest(unittest.TestCase): 27 28 def test_parse_font_invalid_file(self): 29 # File must be string 30 self.assertRaises( 31 AssertionError, 32 parse_font_from_json_for_sanitization_test, 33 """{ "file": [] }""", 34 ) 35 self.assertRaises( 36 AssertionError, 37 parse_font_from_json_for_sanitization_test, 38 """{ "file": -10 }""", 39 ) 40 self.assertRaises( 41 AssertionError, 42 parse_font_from_json_for_sanitization_test, 43 """{ "file": 0.5 }""", 44 ) 45 46 def test_parse_font_invalid_weight(self): 47 # Weight only accept integer or string as integer. 48 self.assertRaises( 49 AssertionError, 50 parse_font_from_json_for_sanitization_test, 51 """{ "weight": [] }""", 52 ) 53 self.assertRaises( 54 AssertionError, 55 parse_font_from_json_for_sanitization_test, 56 """{ "weight": 0.5 }""", 57 ) 58 self.assertRaises( 59 AssertionError, 60 parse_font_from_json_for_sanitization_test, 61 """{ "weight": "0.5" }""", 62 ) 63 self.assertRaises( 64 AssertionError, 65 parse_font_from_json_for_sanitization_test, 66 """{ "weight": -10 }""", 67 ) 68 self.assertRaises( 69 AssertionError, 70 parse_font_from_json_for_sanitization_test, 71 """{ "weight": 1001 }""", 72 ) 73 self.assertRaises( 74 AssertionError, 75 parse_font_from_json_for_sanitization_test, 76 """{ "weight": "-10" }""", 77 ) 78 self.assertRaises( 79 AssertionError, 80 parse_font_from_json_for_sanitization_test, 81 """{ "weight": "1001" }""", 82 ) 83 84 def test_parse_font_invalid_style(self): 85 # Style only accept string "noromal" or "italic" 86 self.assertRaises( 87 AssertionError, 88 parse_font_from_json_for_sanitization_test, 89 """{ "style": [] }""", 90 ) 91 self.assertRaises( 92 AssertionError, 93 parse_font_from_json_for_sanitization_test, 94 """{ "style": 0 }""", 95 ) 96 self.assertRaises( 97 AssertionError, 98 parse_font_from_json_for_sanitization_test, 99 """{ "style": "foo" }""", 100 ) 101 102 def test_parse_font_invalid_index(self): 103 # Index only accepts integer or string as integer that equals or larger than zero. 104 self.assertRaises( 105 AssertionError, 106 parse_font_from_json_for_sanitization_test, 107 """{ "index": [] }""", 108 ) 109 self.assertRaises( 110 AssertionError, 111 parse_font_from_json_for_sanitization_test, 112 """{ "index": "foo" }""", 113 ) 114 self.assertRaises( 115 AssertionError, 116 parse_font_from_json_for_sanitization_test, 117 """{ "index": -1 }""", 118 ) 119 self.assertRaises( 120 AssertionError, 121 parse_font_from_json_for_sanitization_test, 122 """{ "index": "-1" }""", 123 ) 124 125 def test_parse_font_invalid_supportedAxes(self): 126 # The supportedAxes only accepts wght or wght,ital. 127 self.assertRaises( 128 AssertionError, 129 parse_font_from_json_for_sanitization_test, 130 """{ "supportedAxes": [] }""", 131 ) 132 self.assertRaises( 133 AssertionError, 134 parse_font_from_json_for_sanitization_test, 135 """{ "supportedAxes": 0 }""", 136 ) 137 self.assertRaises( 138 AssertionError, 139 parse_font_from_json_for_sanitization_test, 140 """{ "supportedAxes": 0.5 }""", 141 ) 142 self.assertRaises( 143 AssertionError, 144 parse_font_from_json_for_sanitization_test, 145 """{ "supportedAxes": "1" }""", 146 ) 147 self.assertRaises( 148 AssertionError, 149 parse_font_from_json_for_sanitization_test, 150 """{ "supportedAxes": "ital" }""", 151 ) 152 self.assertRaises( 153 AssertionError, 154 parse_font_from_json_for_sanitization_test, 155 """{ "supportedAxes": "wghtital" }""", 156 ) 157 158 def test_parse_font_invalid_post_script_name(self): 159 # The postScriptName only accepts string. 160 self.assertRaises( 161 AssertionError, 162 parse_font_from_json_for_sanitization_test, 163 """{ "postScriptName": [] }""", 164 ) 165 self.assertRaises( 166 AssertionError, 167 parse_font_from_json_for_sanitization_test, 168 """{ "postScriptName": 1 }""", 169 ) 170 self.assertRaises( 171 AssertionError, 172 parse_font_from_json_for_sanitization_test, 173 """{ "postScriptName": 0.5 }""", 174 ) 175 176 def test_parse_font_invalid_axes(self): 177 # The axes accept OpenType tag to float value. 178 self.assertRaises( 179 AssertionError, 180 parse_font_from_json_for_sanitization_test, 181 """{ "axes": [] }""", 182 ) 183 self.assertRaises( 184 AssertionError, 185 parse_font_from_json_for_sanitization_test, 186 """{ "axes": "foo" }""", 187 ) 188 self.assertRaises( 189 AssertionError, 190 parse_font_from_json_for_sanitization_test, 191 """{ "axes": 1 }""", 192 ) 193 self.assertRaises( 194 AssertionError, 195 parse_font_from_json_for_sanitization_test, 196 """{ 197 "axes":{ 198 "wght": "ital" 199 } 200 }""", 201 ) 202 self.assertRaises( 203 AssertionError, 204 parse_font_from_json_for_sanitization_test, 205 """{ 206 "axes":{ 207 "weight": 100 208 } 209 }""", 210 ) 211 212 def test_parse_font_unknown_key(self): 213 self.assertRaises( 214 AssertionError, 215 parse_font_from_json_for_sanitization_test, 216 """{ "font": "Roboto-Regular.ttf" }""", 217 ) 218 219 def test_parse_font_invalid_font(self): 220 # empty fonts are not allowed 221 self.assertRaises( 222 AssertionError, parse_fonts_from_json_for_validation_test, """[]""" 223 ) 224 # At least file should be specified 225 self.assertRaises( 226 AssertionError, parse_fonts_from_json_for_validation_test, """[{}]""" 227 ) 228 # If supportedAxes is not spccified, weight and style should be specified. 229 self.assertRaises( 230 AssertionError, 231 parse_fonts_from_json_for_validation_test, 232 """[{ 233 "file": "Roboto-Regular.ttf", 234 "weight": 400 235 }]""", 236 ) 237 self.assertRaises( 238 AssertionError, 239 parse_fonts_from_json_for_validation_test, 240 """[{ 241 "file": "Roboto-Regular.ttf", 242 "style": "normal" 243 }]""", 244 ) 245 246 def test_parse_font(self): 247 fonts = parse_fonts_from_json_for_validation_test("""[ 248 { 249 "file": "Roboto-Regular.ttf", 250 "weight": 700, 251 "style": "normal", 252 "axes": { 253 "wght": 700 254 } 255 }, { 256 "file": "Roboto-Italic.ttf", 257 "weight": 700, 258 "style": "italic", 259 "axes": { 260 "wght": 700 261 } 262 } 263 ]""") 264 self.assertEqual(2, len(fonts)) 265 266 self.assertEqual("Roboto-Regular.ttf", fonts[0].file) 267 self.assertEqual(700, fonts[0].weight) 268 self.assertEqual("normal", fonts[0].style) 269 self.assertEqual(1, len(fonts[0].axes)) 270 self.assertEqual(700, fonts[0].axes["wght"]) 271 self.assertIsNone(fonts[0].index) 272 self.assertIsNone(fonts[0].supported_axes) 273 self.assertIsNone(fonts[0].post_script_name) 274 275 self.assertEqual("Roboto-Italic.ttf", fonts[1].file) 276 self.assertEqual(700, fonts[1].weight) 277 self.assertEqual("italic", fonts[1].style) 278 self.assertEqual(1, len(fonts[1].axes)) 279 self.assertEqual(700, fonts[1].axes["wght"]) 280 self.assertIsNone(fonts[1].index) 281 self.assertIsNone(fonts[1].supported_axes) 282 self.assertIsNone(fonts[1].post_script_name) 283 284 def test_parse_font2(self): 285 fonts = parse_fonts_from_json_for_validation_test("""[ 286 { 287 "file": "RobotoFlex-Regular.ttf", 288 "supportedAxes": "wght", 289 "axes": { 290 "wdth": 100 291 } 292 } 293 ]""") 294 self.assertEqual(1, len(fonts)) 295 296 self.assertEqual("RobotoFlex-Regular.ttf", fonts[0].file) 297 self.assertEqual(1, len(fonts[0].axes)) 298 self.assertEqual(100, fonts[0].axes["wdth"]) 299 self.assertIsNone(fonts[0].index) 300 self.assertIsNone(fonts[0].weight) 301 self.assertIsNone(fonts[0].style) 302 self.assertIsNone(fonts[0].post_script_name) 303 304 def test_parse_font3(self): 305 fonts = parse_fonts_from_json_for_validation_test("""[ 306 { 307 "file": "SourceSansPro-Regular.ttf", 308 "weight": 400, 309 "style": "normal" 310 }, { 311 "file": "SourceSansPro-Italic.ttf", 312 "weight": 400, 313 "style": "italic" 314 }, { 315 "file": "SourceSansPro-SemiBold.ttf", 316 "weight": 600, 317 "style": "normal" 318 }, { 319 "file": "SourceSansPro-SemiBoldItalic.ttf", 320 "weight": 600, 321 "style": "italic" 322 }, { 323 "file": "SourceSansPro-Bold.ttf", 324 "weight": 700, 325 "style": "normal" 326 }, { 327 "file": "SourceSansPro-BoldItalic.ttf", 328 "weight": 700, 329 "style": "italic" 330 } 331 ]""") 332 333 self.assertEqual(6, len(fonts)) 334 335 self.assertEqual("SourceSansPro-Regular.ttf", fonts[0].file) 336 self.assertEqual(400, fonts[0].weight) 337 self.assertEqual("normal", fonts[0].style) 338 339 self.assertEqual("SourceSansPro-Italic.ttf", fonts[1].file) 340 self.assertEqual(400, fonts[1].weight) 341 self.assertEqual("italic", fonts[1].style) 342 343 self.assertEqual("SourceSansPro-SemiBold.ttf", fonts[2].file) 344 self.assertEqual(600, fonts[2].weight) 345 self.assertEqual("normal", fonts[2].style) 346 347 self.assertEqual("SourceSansPro-SemiBoldItalic.ttf", fonts[3].file) 348 self.assertEqual(600, fonts[3].weight) 349 self.assertEqual("italic", fonts[3].style) 350 351 self.assertEqual("SourceSansPro-Bold.ttf", fonts[4].file) 352 self.assertEqual(700, fonts[4].weight) 353 self.assertEqual("normal", fonts[4].style) 354 355 self.assertEqual("SourceSansPro-BoldItalic.ttf", fonts[5].file) 356 self.assertEqual(700, fonts[5].weight) 357 self.assertEqual("italic", fonts[5].style) 358 359 def test_parse_font4(self): 360 fonts = parse_fonts_from_json_for_validation_test("""[ 361 { 362 "file": "NotoSerifCJK-Regular.ttc", 363 "postScriptName": "NotoSerifCJKjp-Regular", 364 "weight": "400", 365 "style": "normal", 366 "index": "2" 367 } 368 ]""") 369 self.assertEqual(1, len(fonts)) 370 371 self.assertEqual("NotoSerifCJK-Regular.ttc", fonts[0].file) 372 self.assertEqual("NotoSerifCJKjp-Regular", fonts[0].post_script_name) 373 self.assertEqual(400, fonts[0].weight) 374 self.assertEqual("normal", fonts[0].style) 375 self.assertEqual(2, fonts[0].index) 376 377 378if __name__ == "__main__": 379 unittest.main(verbosity=2) 380