11"""Tests for the Tools/i18n/msgfmt.py tool."""
22
33import json
4+ import os
45import struct
56import sys
67import unittest
@@ -244,80 +245,108 @@ def test_strings(self):
244245 msgfmt .make ('messages.po' , 'messages.mo' )
245246
246247 def test_general_syntax_errors (self ):
248+ # 2-tuples of input PO files and expected error messages
247249 invalid_po_files = (
248- '' ,
249- '"' ,
250- '""' ,
251- '"foo"' ,
250+ ( '' , None ) ,
251+ ( '"' , None ) ,
252+ ( '""' , 'Syntax error on messages.po:1 before:' ) ,
253+ ( '"foo"' , f'Syntax error on messages.po:1 before: { os . linesep } foo' ) ,
252254 # 'msgid', # invalid but currently accepted
253- 'msgstr' ,
254- 'msgid_plural' ,
255+ ( 'msgstr' , None ) ,
256+ ( 'msgid_plural' , 'msgid_plural not preceded by msgid on messages.po:1' ) ,
255257 # 'msgctxt', # invalid but currently accepted
256- 'msgstr' ,
257- 'msgstr[0]' ,
258- '[0]' ,
258+ ( 'msgstr' , None ) ,
259+ ( 'msgstr[0]' , None ) ,
260+ ( '[0]' , f'Syntax error on messages.po:1 before: { os . linesep } [0]' ) ,
259261
260262 # unclosed string
261- dedent ('''\
262- msgid "
263- msgstr "bar"
264- ''' ),
263+ (
264+ dedent ('''\
265+ msgid "
266+ msgstr "bar"
267+ ''' ),
268+ None
269+ ),
265270
266271 # unclosed string
267- dedent ('''\
268- msgid "foo
269- msgstr "bar"
270- ''' ),
272+ (
273+ dedent ('''\
274+ msgid "foo
275+ msgstr "bar"
276+ ''' ),
277+ None
278+ ),
271279
272280 # unclosed string
273- dedent ('''\
274- msgid "foo" "
275- msgstr "bar"
276- ''' ),
281+ (
282+ dedent ('''\
283+ msgid "foo" "
284+ msgstr "bar"
285+ ''' ),
286+ None
287+ ),
277288
278289 # unclosed string
279- dedent ('''\
280- msgid "foo"
281- "
282- msgstr "bar"
283- ''' ),
290+ (
291+ dedent ('''\
292+ msgid "foo"
293+ "
294+ msgstr "bar"
295+ ''' ),
296+ None
297+ ),
284298
285299 # illegal backslash
286- dedent ('''\
287- msgid "foo\\ "
288- "
289- msgstr "bar"
290- ''' ),
300+ (
301+ dedent ('''\
302+ msgid "foo\\ "
303+ "
304+ msgstr "bar"
305+ ''' ),
306+ None
307+ ),
291308
292309 # msgid with an index
293- dedent ('''\
294- msgid[0] "foo"
295- msgstr "bar"
296- ''' ),
310+ (
311+ dedent ('''\
312+ msgid[0] "foo"
313+ msgstr "bar"
314+ ''' ),
315+ None
316+ ),
297317
298318 # invalid plural index
299- dedent ('''\
300- msgid "foo"
301- msgid_plural "foos"
302- msgstr[0 "baz"
303- ''' ),
319+ (
320+ dedent ('''\
321+ msgid "foo"
322+ msgid_plural "foos"
323+ msgstr[0 "baz"
324+ ''' ),
325+ None
326+ ),
304327
305328 # invalid plural index
306- dedent ('''\
307- msgid "foo"
308- msgid_plural "foos"
309- msgstr1] "baz"
310- ''' ),
329+ (
330+ dedent ('''\
331+ msgid "foo"
332+ msgid_plural "foos"
333+ msgstr1] "baz"
334+ ''' ),
335+ 'indexed msgstr required for plural on messages.po:3'
336+ ),
311337
312338 # invalid plural index
313- dedent ('''\
314- msgid "foo"
315- msgid_plural "foos"
316- msgstr[[0]] "baz"
317- ''' ),
339+ (
340+ dedent ('''\
341+ msgid "foo"
342+ msgid_plural "foos"
343+ msgstr[[0]] "baz"
344+ ''' ),
345+ None
346+ )
318347 )
319348 with temp_cwd ():
320- for invalid_po in invalid_po_files :
349+ for invalid_po , err_msg in invalid_po_files :
321350 with self .subTest (invalid_po = invalid_po ):
322351 Path ('messages.po' ).write_text (invalid_po )
323352 # Reset the global MESSAGES dictionary
@@ -326,99 +355,130 @@ def test_general_syntax_errors(self):
326355 with self .assertRaises ((SystemExit , UnboundLocalError ,
327356 IndexError , SyntaxError )):
328357 msgfmt .make ('messages.po' , 'messages.mo' )
358+ if err_msg :
359+ self .assertEqual (output .getvalue ().strip (), err_msg )
329360
330361 def test_semantic_errors (self ):
362+ # 2-tuples of input PO files and expected error messages
331363 invalid_po_files = (
332364 # msgid_plural must be preceded by msgid
333- dedent ('''\
334- msgid_plural "foos"
365+ (
366+ dedent ('''\
367+ msgid_plural "foos"
335368
336- msgid "bar"
337- msgstr "baz"
338- ''' ),
369+ msgid "bar"
370+ msgstr "baz"
371+ ''' ),
372+ 'msgid_plural not preceded by msgid on messages.po:1'
373+ ),
339374
340375 # msgid_plural not allowed after comment
341- dedent ('''\
342- # comment
343- msgid_plural "foos"
376+ (
377+ dedent ('''\
378+ # comment
379+ msgid_plural "foos"
344380
345- msgid "bar"
346- msgstr "baz"
347- ''' ),
381+ msgid "bar"
382+ msgstr "baz"
383+ ''' ),
384+ 'msgid_plural not preceded by msgid on messages.po:2'
385+ ),
348386
349387 # msgid_plural not allowed after msgctxt
350- dedent ('''\
351- msgctxt "foo"
352- msgid_plural "foos"
388+ (
389+ dedent ('''\
390+ msgctxt "foo"
391+ msgid_plural "foos"
353392
354- msgid "bar"
355- msgstr "baz"
356- ''' ),
393+ msgid "bar"
394+ msgstr "baz"
395+ ''' ),
396+ 'msgid_plural not preceded by msgid on messages.po:2'
397+ ),
357398
358399 # msgid_plural not allowed after msgstr
359- dedent ('''\
360- msgid "foo"
361- msgstr "bar"
362- msgid_plural "foos"
363-
364- msgid "bar"
365- msgstr "baz"
366- ''' ),
400+ (
401+ dedent ('''\
402+ msgid "foo"
403+ msgstr "bar"
404+ msgid_plural "foos"
405+
406+ msgid "bar"
407+ msgstr "baz"
408+ ''' ),
409+ 'msgid_plural not preceded by msgid on messages.po:3'
410+ ),
367411
368412 # msgstr must be preceded by msgid
369- dedent ('''\
370- msgstr "foo"
413+ (
414+ dedent ('''\
415+ msgstr "foo"
371416
372- msgid "bar"
373- msgstr "baz"
374- ''' ),
417+ msgid "bar"
418+ msgstr "baz"
419+ ''' ),
420+ None
421+ ),
375422
376423 # msgstr not allowed after msgctxt
377- dedent ('''\
378- msgctxt "foo"
379- msgstr "bar"
424+ (
425+ dedent ('''\
426+ msgctxt "foo"
427+ msgstr "bar"
380428
381- msgid "foo"
382- msgstr "bar"
383- ''' ),
429+ msgid "foo"
430+ msgstr "bar"
431+ ''' ),
432+ None
433+ ),
384434
385435 # missing msgid_plural section
386- dedent ('''\
387- msgid "foo"
388- msgstr[0] "bar"
389-
390- msgid "bar"
391- msgstr "baz"
392- ''' ),
436+ (
437+ dedent ('''\
438+ msgid "foo"
439+ msgstr[0] "bar"
440+
441+ msgid "bar"
442+ msgstr "baz"
443+ ''' ),
444+ 'plural without msgid_plural on messages.po:2'
445+ ),
393446 )
394447 with temp_cwd ():
395- for invalid_po in invalid_po_files :
448+ for invalid_po , err_msg in invalid_po_files :
396449 with self .subTest (invalid_po = invalid_po ):
397450 Path ('messages.po' ).write_text (invalid_po )
398451 # Reset the global MESSAGES dictionary
399452 msgfmt .MESSAGES .clear ()
400453 with redirect_stderr (StringIO ()) as output :
401454 with self .assertRaises ((SystemExit , UnboundLocalError )):
402455 msgfmt .make ('messages.po' , 'messages.mo' )
456+ if err_msg :
457+ self .assertEqual (output .getvalue ().strip (), err_msg )
403458
404459 def test_msgstr_invalid_indices (self ):
460+ # 2-tuples of input PO files and expected error messages
405461 invalid_po_files = (
406462 # msgstr not pluralized
407- dedent ('''\
408- msgid "foo"
409- msgid_plural "foos"
410- msgstr "bar"
411- ''' ),
463+ (
464+ dedent ('''\
465+ msgid "foo"
466+ msgid_plural "foos"
467+ msgstr "bar"
468+ ''' ),
469+ 'indexed msgstr required for plural on messages.po:3'
470+ ),
412471 )
413472 with temp_cwd ():
414- for invalid_po in invalid_po_files :
473+ for invalid_po , err_msg in invalid_po_files :
415474 with self .subTest (invalid_po = invalid_po ):
416475 Path ('messages.po' ).write_text (invalid_po )
417476 # Reset the global MESSAGES dictionary
418477 msgfmt .MESSAGES .clear ()
419478 with redirect_stderr (StringIO ()) as output :
420479 with self .assertRaises (SystemExit ):
421480 msgfmt .make ('messages.po' , 'messages.mo' )
481+ self .assertEqual (output .getvalue ().strip (), err_msg )
422482
423483
424484class CLITest (unittest .TestCase ):
0 commit comments