1 # Stricter version of the export tests: validate the XHTML code produced by
2 # LyX' lyxhtml output as HTML5. It also validates the CSS and MathML parts.
3 # Validation errors usually are mistakes in the generator.
6 # python lyxhtml_validity.py PATH_TO_LYX/lyx
8 # Written with Python 3.8.8.
10 # - Python package: html5validator: at least v0.4.2
11 # - Java runtime engine (JRE): at least v8 (depending on html5validator)
13 # pip install html5validator>=0.4.2
24 if len(sys.argv) != 2:
25 print('Expecting one argument, the path to the LyX binary to test')
27 if not os.path.exists(sys.argv[1]):
28 print('The given path does not point to an existing file')
30 if not os.access(sys.argv[1], os.X_OK):
31 print('The given path does not point to an executable file')
35 PATH_SCRIPT = os.path.dirname(os.path.realpath(__file__))
36 PATH_EXPORT_TESTS = os.path.realpath(PATH_SCRIPT + '/../../autotests/export/')
37 PATH_LYX = sys.argv[1]
40 TestFile = collections.namedtuple(
41 "TestFile", ["lyx_path", "lyx_file_name", "xhtml_path", "xhtml_file_name"]
44 validator = html5validator.Validator(format='text')
47 with tempfile.TemporaryDirectory() as out_dir_name:
48 all_lyx_files = glob.glob(PATH_EXPORT_TESTS + '/**/*.lyx', recursive=True)
52 lyx_file_name=os.path.basename(path),
53 xhtml_path = os.path.join(out_dir_name, os.path.basename(path)),
54 xhtml_file_name=os.path.basename(path).replace('.lyx', '.html')
55 ) for path in all_lyx_files
58 # Generate XHTML files.
60 f'Exporting {len(all_lyx_files)} LyX files to LyXHTML format in the ' +
61 f'directory {out_dir_name}'
64 for file in all_files:
65 print(f'* Generating {file.lyx_file_name}...')
66 os.system(f'{PATH_LYX} --export-to xhtml "{file.xhtml_path}" "{file.lyx_path}"')
67 print(f'> Done generating {file.lyx_path} to {file.xhtml_path}')
70 # print(open(file.xhtml_path, 'r').read())
72 print(f'Exported successfully all {len(all_lyx_files)} files!')
74 # Validate the XHTML files.
75 print(f'Validating {len(all_lyx_files)} XHTML files...')
79 for file in all_files:
80 print(f'* Validating {file.xhtml_file_name}...')
81 error_count = validator.validate([file.xhtml_file_name])
82 # Caution: this call outputs all validation errors to stdout!
83 # This line is equivalent to running vnu on the corresponding file.
84 # https://github.com/validator/validator
88 print(f'> Found no validation error!')
91 print(f'> Found {error_count} validation error{"" if error_count == 1 else "s"}!')
93 print(f'Validated all {len(all_lyx_files)} files! Among them:')
94 print(f'> {n_valid} were valid ({100.0 * n_valid / len(all_files)}%)')
95 print(f'> {n_invalid} were invalid ({100.0 * n_invalid / len(all_files)}%)')
98 print("That's excellent! Give yourself a pat on the back!")
99 elif 100.0 * n_invalid / len(all_files) <= 5.0:
100 print("That's a pretty good job!")