summaryrefslogtreecommitdiffstats
path: root/unittests/datatests.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unittests/datatests.py242
1 files changed, 242 insertions, 0 deletions
diff --git a/unittests/datatests.py b/unittests/datatests.py
new file mode 100644
index 0000000..9a46ec4
--- /dev/null
+++ b/unittests/datatests.py
@@ -0,0 +1,242 @@
+# Copyright 2016-2021 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import unittest
+from itertools import chain
+from pathlib import Path
+
+import mesonbuild.mlog
+import mesonbuild.depfile
+import mesonbuild.dependencies.base
+import mesonbuild.dependencies.factory
+import mesonbuild.envconfig
+import mesonbuild.environment
+import mesonbuild.coredata
+import mesonbuild.modules.gnome
+from mesonbuild.interpreter import Interpreter
+from mesonbuild.ast import AstInterpreter
+from mesonbuild.mesonlib import (
+ MachineChoice, OptionKey
+)
+from mesonbuild.compilers import (
+ detect_c_compiler, detect_cpp_compiler
+)
+import mesonbuild.modules.pkgconfig
+
+
+from run_tests import (
+ FakeBuild, get_fake_env
+)
+
+from .helpers import *
+
+@unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release')
+class DataTests(unittest.TestCase):
+
+ def test_snippets(self):
+ hashcounter = re.compile('^ *(#)+')
+ snippet_dir = Path('docs/markdown/snippets')
+ self.assertTrue(snippet_dir.is_dir())
+ for f in snippet_dir.glob('*'):
+ self.assertTrue(f.is_file())
+ if f.parts[-1].endswith('~'):
+ continue
+ if f.suffix == '.md':
+ in_code_block = False
+ with f.open(encoding='utf-8') as snippet:
+ for line in snippet:
+ if line.startswith(' '):
+ continue
+ if line.startswith('```'):
+ in_code_block = not in_code_block
+ if in_code_block:
+ continue
+ m = re.match(hashcounter, line)
+ if m:
+ self.assertEqual(len(m.group(0)), 2, 'All headings in snippets must have two hash symbols: ' + f.name)
+ self.assertFalse(in_code_block, 'Unclosed code block.')
+ else:
+ if f.name != 'add_release_note_snippets_here':
+ self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name)
+
+ def test_compiler_options_documented(self):
+ '''
+ Test that C and C++ compiler options and base options are documented in
+ Builtin-Options.md. Only tests the default compiler for the current
+ platform on the CI.
+ '''
+ md = None
+ with open('docs/markdown/Builtin-options.md', encoding='utf-8') as f:
+ md = f.read()
+ self.assertIsNotNone(md)
+ env = get_fake_env()
+ # FIXME: Support other compilers
+ cc = detect_c_compiler(env, MachineChoice.HOST)
+ cpp = detect_cpp_compiler(env, MachineChoice.HOST)
+ for comp in (cc, cpp):
+ for opt in comp.get_options():
+ self.assertIn(str(opt), md)
+ for opt in comp.base_options:
+ self.assertIn(str(opt), md)
+ self.assertNotIn('b_unknown', md)
+
+ @staticmethod
+ def _get_section_content(name, sections, md):
+ for section in sections:
+ if section and section.group(1) == name:
+ try:
+ next_section = next(sections)
+ end = next_section.start()
+ except StopIteration:
+ end = len(md)
+ # Extract the content for this section
+ return md[section.end():end]
+ raise RuntimeError(f'Could not find "{name}" heading')
+
+ def test_builtin_options_documented(self):
+ '''
+ Test that universal options and base options are documented in
+ Builtin-Options.md.
+ '''
+ from itertools import tee
+ md = None
+ with open('docs/markdown/Builtin-options.md', encoding='utf-8') as f:
+ md = f.read()
+ self.assertIsNotNone(md)
+
+ found_entries = set()
+ sections = re.finditer(r"^## (.+)$", md, re.MULTILINE)
+ # Extract the content for this section
+ u_subcontents = []
+ content = self._get_section_content("Universal options", sections, md)
+ subsections = tee(re.finditer(r"^### (.+)$", content, re.MULTILINE))
+ u_subcontents.append(self._get_section_content("Directories", subsections[0], content))
+ u_subcontents.append(self._get_section_content("Core options", subsections[1], content))
+
+ mod_subcontents = []
+ content = self._get_section_content("Module options", sections, md)
+ subsections = tee(re.finditer(r"^### (.+)$", content, re.MULTILINE))
+ for idx, mod in enumerate(['Pkgconfig', 'Python']):
+ mod_subcontents.append(self._get_section_content(f'{mod} module', subsections[idx], content))
+ for subcontent in u_subcontents + mod_subcontents:
+ # Find the option names
+ options = set()
+ # Match either a table row or a table heading separator: | ------ |
+ rows = re.finditer(r"^\|(?: (\w+) .* | *-+ *)\|", subcontent, re.MULTILINE)
+ # Skip the header of the first table
+ next(rows)
+ # Skip the heading separator of the first table
+ next(rows)
+ for m in rows:
+ value = m.group(1)
+ # End when the `buildtype` table starts
+ if value is None:
+ break
+ options.add(value)
+ self.assertEqual(len(found_entries & options), 0)
+ found_entries |= options
+
+ self.assertEqual(found_entries, {
+ *(str(k.evolve(module=None)) for k in mesonbuild.coredata.BUILTIN_OPTIONS),
+ *(str(k.evolve(module=None)) for k in mesonbuild.coredata.BUILTIN_OPTIONS_PER_MACHINE),
+ })
+
+ # Check that `buildtype` table inside `Core options` matches how
+ # setting of builtin options behaves
+ #
+ # Find all tables inside this subsection
+ tables = re.finditer(r"^\| (\w+) .* \|\n\| *[-|\s]+ *\|$", u_subcontents[1], re.MULTILINE)
+ # Get the table we want using the header of the first column
+ table = self._get_section_content('buildtype', tables, u_subcontents[1])
+ # Get table row data
+ rows = re.finditer(r"^\|(?: (\w+)\s+\| (\w+)\s+\| (\w+) .* | *-+ *)\|", table, re.MULTILINE)
+ env = get_fake_env()
+ for m in rows:
+ buildtype, debug, opt = m.groups()
+ if debug == 'true':
+ debug = True
+ elif debug == 'false':
+ debug = False
+ else:
+ raise RuntimeError(f'Invalid debug value {debug!r} in row:\n{m.group()}')
+ env.coredata.set_option(OptionKey('buildtype'), buildtype)
+ self.assertEqual(env.coredata.options[OptionKey('buildtype')].value, buildtype)
+ self.assertEqual(env.coredata.options[OptionKey('optimization')].value, opt)
+ self.assertEqual(env.coredata.options[OptionKey('debug')].value, debug)
+
+ def test_cpu_families_documented(self):
+ with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f:
+ md = f.read()
+ self.assertIsNotNone(md)
+
+ sections = re.finditer(r"^## (.+)$", md, re.MULTILINE)
+ content = self._get_section_content("CPU families", sections, md)
+ # Find the list entries
+ arches = [m.group(1) for m in re.finditer(r"^\| (\w+) +\|", content, re.MULTILINE)]
+ # Drop the header
+ arches = set(arches[1:])
+ self.assertEqual(arches, set(mesonbuild.environment.known_cpu_families))
+
+ def test_markdown_files_in_sitemap(self):
+ '''
+ Test that each markdown files in docs/markdown is referenced in sitemap.txt
+ '''
+ with open("docs/sitemap.txt", encoding='utf-8') as f:
+ md = f.read()
+ self.assertIsNotNone(md)
+ toc = list(m.group(1) for m in re.finditer(r"^\s*(\w.*)$", md, re.MULTILINE))
+ markdownfiles = [f.name for f in Path("docs/markdown").iterdir() if f.is_file() and f.suffix == '.md']
+ exceptions = ['_Sidebar.md']
+ for f in markdownfiles:
+ if f not in exceptions and not f.startswith('_include'):
+ self.assertIn(f, toc)
+
+ def test_modules_in_navbar(self):
+ '''
+ Test that each module is referenced in navbar_links.html
+ '''
+ with open("docs/theme/extra/templates/navbar_links.html", encoding='utf-8') as f:
+ html = f.read().lower()
+ self.assertIsNotNone(html)
+ for f in Path('mesonbuild/modules').glob('*.py'):
+ if f.name in {'modtest.py', 'qt.py', '__init__.py'}:
+ continue
+ name = f'{f.stem}-module.html'
+ name = name.replace('unstable_', '')
+ name = name.replace('python3', 'python-3')
+ name = name.replace('_', '-')
+ self.assertIn(name, html)
+
+ def test_vim_syntax_highlighting(self):
+ '''
+ Ensure that vim syntax highlighting files were updated for new
+ functions in the global namespace in build files.
+ '''
+ env = get_fake_env()
+ interp = Interpreter(FakeBuild(env), mock=True)
+ with open('data/syntax-highlighting/vim/syntax/meson.vim', encoding='utf-8') as f:
+ res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE)
+ defined = set([a.strip() for a in res.group().split('\\')][1:])
+ self.assertEqual(defined, set(chain(interp.funcs.keys(), interp.builtin.keys())))
+
+ def test_all_functions_defined_in_ast_interpreter(self):
+ '''
+ Ensure that the all functions defined in the Interpreter are also defined
+ in the AstInterpreter (and vice versa).
+ '''
+ env = get_fake_env()
+ interp = Interpreter(FakeBuild(env), mock=True)
+ astint = AstInterpreter('.', '', '')
+ self.assertEqual(set(interp.funcs.keys()), set(astint.funcs.keys()))