@@ -240,6 +240,362 @@ def test_strings(self):
240240 with self .assertRaises (Exception ):
241241 msgfmt .make ('messages.po' , 'messages.mo' )
242242
243+ def test_general_syntax_errors (self ):
244+ invalid_po_files = (
245+ '' ,
246+ '"' ,
247+ '""' ,
248+ '"foo"' ,
249+ # 'msgid', # invalid but currently accepted
250+ 'msgstr' ,
251+ 'msgid_plural' ,
252+ # 'msgctxt', # invalid but currently accepted
253+ 'msgstr' ,
254+ 'msgstr[0]' ,
255+ '[0]' ,
256+
257+ # unclosed string
258+ '''
259+ msgid "
260+ msgstr "bar"
261+ ''' ,
262+
263+ # unclosed string
264+ '''
265+ msgid "foo
266+ msgstr "bar"
267+ ''' ,
268+
269+ # unclosed string
270+ '''
271+ msgid "foo" "
272+ msgstr "bar"
273+ ''' ,
274+
275+ # unclosed string
276+ '''
277+ msgid "foo"
278+ "
279+ msgstr "bar"
280+ ''' ,
281+
282+ # illegal backslash
283+ '''
284+ msgid "foo\\ "
285+ "
286+ msgstr "bar"
287+ ''' ,
288+
289+ # msgid with an index
290+ '''
291+ msgid[0] "foo"
292+ msgstr "bar"
293+ ''' ,
294+
295+ # invalid plural index
296+ # invalid but currently accepted
297+ # '''
298+ # msgid "foo"
299+ # msgid_plural "foos"
300+ # msgstr[foo] "baz"
301+ # ''',
302+
303+ # invalid plural index
304+ '''
305+ msgid "foo"
306+ msgid_plural "foos"
307+ msgstr[0 "baz"
308+ ''' ,
309+
310+ # invalid plural index
311+ # invalid but currently accepted
312+ # '''
313+ # msgid "foo"
314+ # msgid_plural "foos"
315+ # msgstr[] "baz"
316+ # ''',
317+
318+ # invalid plural index
319+ '''
320+ msgid "foo"
321+ msgid_plural "foos"
322+ msgstr1] "baz"
323+ ''' ,
324+
325+ # invalid plural index
326+ '''
327+ msgid "foo"
328+ msgid_plural "foos"
329+ msgstr[[0]] "baz"
330+ ''' ,
331+ )
332+ with temp_cwd ():
333+ for invalid_po in invalid_po_files :
334+ with self .subTest (invalid_po = invalid_po ):
335+ Path ('messages.po' ).write_text (invalid_po )
336+ # Reset the global MESSAGES dictionary
337+ msgfmt .MESSAGES .clear ()
338+ with self .assertRaises ((SystemExit , UnboundLocalError ,
339+ IndexError , SyntaxError )):
340+ msgfmt .make ('messages.po' , 'messages.mo' )
341+
342+ def test_semantic_errors (self ):
343+ invalid_po_files = (
344+ # missing msgid after msgctxt
345+ # invalid but currently accepted
346+ # 'msgctxt "foo"',
347+
348+ # missing msgstr after msgid
349+ # invalid but currently accepted
350+ # 'msgid "foo"',
351+
352+ # comment line not allowed after msgctxt
353+ # invalid but currently accepted
354+ # '''
355+ # msgctxt "foo"
356+ # # comment
357+ # msgid "bar"
358+ # msgstr "bar"
359+ # ''',
360+
361+ # comment line not allowed after msgid
362+ # invalid but currently accepted
363+ # '''
364+ # msgid "foo"
365+ # # comment
366+ # msgstr "bar"
367+ # ''',
368+
369+ # comment line not allowed after msgid_plural
370+ # invalid but currently accepted
371+ # '''
372+ # msgid "foo"
373+ # msgid_plural "foos"
374+ # # comment
375+ # msgstr[0] "bar"
376+ # ''',
377+
378+ # msgctxt not allowed after msgctxt
379+ # invalid but currently accepted
380+ # '''
381+ # msgctxt "foo"
382+
383+ # msgctxt "bar"
384+ # msgid "foo"
385+ # msgstr "bar"
386+ # ''',
387+
388+ # msgctxt not allowed after msgid
389+ # invalid but currently accepted
390+ # '''
391+ # msgid "foo"
392+ # msgctxt "bar"
393+
394+ # msgid "bar"
395+ # msgstr "baz"
396+ # ''',
397+
398+ # msgctxt not allowed after msgid_plural
399+ # invalid but currently accepted
400+ # '''
401+ # msgid "foo"
402+ # msgid_plural "foos"
403+ # msgctxt "bar"
404+
405+ # msgid "bar"
406+ # msgstr "baz"
407+ # ''',
408+
409+ # msgid not allowed after msgid
410+ # invalid but currently accepted
411+ # '''
412+ # msgid "foo"
413+
414+ # msgid "bar"
415+ # msgstr "baz"
416+ # ''',
417+
418+ # msgid not allowed after msgid_plural
419+ # invalid but currently accepted
420+ # '''
421+ # msgid "foo"
422+ # msgid_plural "foos"
423+
424+ # msgid "bar"
425+ # msgstr "baz"
426+ # ''',
427+
428+ # msgid_plural must be preceded by msgid
429+ '''
430+ msgid_plural "foos"
431+
432+ msgid "bar"
433+ msgstr "baz"
434+ ''' ,
435+
436+ # msgid_plural not allowed after comment
437+ '''
438+ # comment
439+ msgid_plural "foos"
440+
441+ msgid "bar"
442+ msgstr "baz"
443+ ''' ,
444+
445+ # msgid_plural not allowed after msgid_plural
446+ # invalid but currently accepted
447+ # '''
448+ # msgid "foo"
449+ # msgid_plural "foos"
450+ # msgid_plural "bars"
451+
452+ # msgid "bar"
453+ # msgstr "baz"
454+ # ''',
455+
456+ # msgid_plural not allowed after msgctxt
457+ '''
458+ msgctxt "foo"
459+ msgid_plural "foos"
460+
461+ msgid "bar"
462+ msgstr "baz"
463+ ''' ,
464+
465+ # msgid_plural not allowed after msgstr
466+ '''
467+ msgid "foo"
468+ msgstr "bar"
469+ msgid_plural "foos"
470+
471+ msgid "bar"
472+ msgstr "baz"
473+ ''' ,
474+
475+ # msgstr must be preceded by msgid
476+ '''
477+ msgstr "foo"
478+
479+ msgid "bar"
480+ msgstr "baz"
481+ ''' ,
482+
483+ # msgstr not allowed after comment
484+ # invalid but currently accepted
485+ # '''
486+ # # comment
487+ # # msgstr "foo"
488+
489+ # msgid "bar"
490+ # msgstr "baz"
491+ # ''',
492+
493+ # msgstr not allowed after msgctxt
494+ '''
495+ msgctxt "foo"
496+ msgstr "bar"
497+
498+ msgid "foo"
499+ msgstr "bar"
500+ ''' ,
501+
502+ # msgstr not allowed after msgstr
503+ # invalid but currently accepted
504+ # '''
505+ # msgid "foo"
506+ # msgstr "bar"
507+ # msgstr "baz"
508+
509+ # msgid "bar"
510+ # msgstr "baz"
511+ # ''',
512+
513+ # missing msgid_plural section
514+ '''
515+ msgid "foo"
516+ msgstr[0] "bar"
517+
518+ msgid "bar"
519+ msgstr "baz"
520+ '''
521+ )
522+ with temp_cwd ():
523+ for invalid_po in invalid_po_files :
524+ with self .subTest (invalid_po = invalid_po ):
525+ Path ('messages.po' ).write_text (invalid_po )
526+ # Reset the global MESSAGES dictionary
527+ msgfmt .MESSAGES .clear ()
528+ with self .assertRaises ((SystemExit , UnboundLocalError )):
529+ msgfmt .make ('messages.po' , 'messages.mo' )
530+
531+ def test_msgstr_invalid_indices (self ):
532+ invalid_po_files = (
533+ # wrong plural form index
534+ # invalid but currently accepted
535+ # '''
536+ # msgid "foo"
537+ # msgid_plural "foos"
538+ # msgstr[42] "bar"
539+ # ''',
540+
541+ # wrong plural form index
542+ # invalid but currently accepted
543+ # '''
544+ # msgid "foo"
545+ # msgid_plural "foos"
546+ # msgstr[0] "bar"
547+ # msgstr[42] "bars"
548+ # ''',
549+
550+ # msgstr not pluralized
551+ '''
552+ msgid "foo"
553+ msgid_plural "foos"
554+ msgstr "bar"
555+ ''' ,
556+ )
557+ with temp_cwd ():
558+ for invalid_po in invalid_po_files :
559+ with self .subTest (invalid_po = invalid_po ):
560+ Path ('messages.po' ).write_text (invalid_po )
561+ # Reset the global MESSAGES dictionary
562+ msgfmt .MESSAGES .clear ()
563+ with self .assertRaises (SystemExit ):
564+ msgfmt .make ('messages.po' , 'messages.mo' )
565+
566+ def test_duplicate_entries (self ):
567+ invalid_po_files = (
568+ # duplicate msgid
569+ # invalid but currently accepted
570+ # '''
571+ # msgid "foo"
572+ # msgstr "bar"
573+
574+ # msgid "foo"
575+ # msgstr "baz"
576+ # ''',
577+
578+ # duplicate msgctxt+msgid
579+ # invalid but currently accepted
580+ # '''
581+ # msgctxt "context"
582+ # msgid "foo"
583+ # msgstr "bar"
584+
585+ # msgctxt "context"
586+ # msgid "foo"
587+ # msgstr "baz"
588+ # '''
589+ )
590+ with temp_cwd ():
591+ for invalid_po in invalid_po_files :
592+ with self .subTest (invalid_po = invalid_po ):
593+ Path ('messages.po' ).write_text (invalid_po )
594+ # Reset the global MESSAGES dictionary
595+ msgfmt .MESSAGES .clear ()
596+ with self .assertRaises (SystemExit ):
597+ msgfmt .make ('messages.po' , 'messages.mo' )
598+
243599
244600class CLITest (unittest .TestCase ):
245601
0 commit comments