# SPDX-License-Identifier: Apache-2.0 # Copyright © 2022-2023 Intel Corporation from __future__ import annotations import unittest import os import tempfile import textwrap import typing as T from mesonbuild.cargo import builder, cfg, load_wraps from mesonbuild.cargo.cfg import TokenType from mesonbuild.cargo.version import convert class CargoVersionTest(unittest.TestCase): def test_cargo_to_meson(self) -> None: cases: T.List[T.Tuple[str, T.List[str]]] = [ # Basic requirements ('>= 1', ['>= 1']), ('> 1', ['> 1']), ('= 1', ['= 1']), ('< 1', ['< 1']), ('<= 1', ['<= 1']), # tilde tests ('~1', ['>= 1', '< 2']), ('~1.1', ['>= 1.1', '< 1.2']), ('~1.1.2', ['>= 1.1.2', '< 1.2.0']), # Wildcards ('*', []), ('1.*', ['>= 1', '< 2']), ('2.3.*', ['>= 2.3', '< 2.4']), # Unqualified ('2', ['>= 2', '< 3']), ('2.4', ['>= 2.4', '< 3']), ('2.4.5', ['>= 2.4.5', '< 3']), ('0.0.0', ['< 1']), ('0.0', ['< 1']), ('0', ['< 1']), ('0.0.5', ['>= 0.0.5', '< 0.0.6']), ('0.5.0', ['>= 0.5.0', '< 0.6']), ('0.5', ['>= 0.5', '< 0.6']), ('1.0.45', ['>= 1.0.45', '< 2']), # Caret (Which is the same as unqualified) ('^2', ['>= 2', '< 3']), ('^2.4', ['>= 2.4', '< 3']), ('^2.4.5', ['>= 2.4.5', '< 3']), ('^0.0.0', ['< 1']), ('^0.0', ['< 1']), ('^0', ['< 1']), ('^0.0.5', ['>= 0.0.5', '< 0.0.6']), ('^0.5.0', ['>= 0.5.0', '< 0.6']), ('^0.5', ['>= 0.5', '< 0.6']), # Multiple requirements ('>= 1.2.3, < 1.4.7', ['>= 1.2.3', '< 1.4.7']), ] for (data, expected) in cases: with self.subTest(): self.assertListEqual(convert(data), expected) class CargoCfgTest(unittest.TestCase): def test_lex(self) -> None: cases: T.List[T.Tuple[str, T.List[T.Tuple[TokenType, T.Optional[str]]]]] = [ ('"unix"', [(TokenType.STRING, 'unix')]), ('unix', [(TokenType.IDENTIFIER, 'unix')]), ('not(unix)', [ (TokenType.NOT, None), (TokenType.LPAREN, None), (TokenType.IDENTIFIER, 'unix'), (TokenType.RPAREN, None), ]), ('any(unix, windows)', [ (TokenType.ANY, None), (TokenType.LPAREN, None), (TokenType.IDENTIFIER, 'unix'), (TokenType.COMMA, None), (TokenType.IDENTIFIER, 'windows'), (TokenType.RPAREN, None), ]), ('target_arch = "x86_64"', [ (TokenType.IDENTIFIER, 'target_arch'), (TokenType.EQUAL, None), (TokenType.STRING, 'x86_64'), ]), ('all(target_arch = "x86_64", unix)', [ (TokenType.ALL, None), (TokenType.LPAREN, None), (TokenType.IDENTIFIER, 'target_arch'), (TokenType.EQUAL, None), (TokenType.STRING, 'x86_64'), (TokenType.COMMA, None), (TokenType.IDENTIFIER, 'unix'), (TokenType.RPAREN, None), ]), ] for data, expected in cases: with self.subTest(): self.assertListEqual(list(cfg.lexer(data)), expected) def test_parse(self) -> None: cases = [ ('target_os = "windows"', cfg.Equal(cfg.Identifier("target_os"), cfg.String("windows"))), ('target_arch = "x86"', cfg.Equal(cfg.Identifier("target_arch"), cfg.String("x86"))), ('target_family = "unix"', cfg.Equal(cfg.Identifier("target_family"), cfg.String("unix"))), ('any(target_arch = "x86", target_arch = "x86_64")', cfg.Any( [ cfg.Equal(cfg.Identifier("target_arch"), cfg.String("x86")), cfg.Equal(cfg.Identifier("target_arch"), cfg.String("x86_64")), ])), ('all(target_arch = "x86", target_os = "linux")', cfg.All( [ cfg.Equal(cfg.Identifier("target_arch"), cfg.String("x86")), cfg.Equal(cfg.Identifier("target_os"), cfg.String("linux")), ])), ('not(all(target_arch = "x86", target_os = "linux"))', cfg.Not( cfg.All( [ cfg.Equal(cfg.Identifier("target_arch"), cfg.String("x86")), cfg.Equal(cfg.Identifier("target_os"), cfg.String("linux")), ]))), ] for data, expected in cases: with self.subTest(): self.assertEqual(cfg.parse(iter(cfg.lexer(data))), expected) def test_ir_to_meson(self) -> None: build = builder.Builder('') HOST_MACHINE = build.identifier('host_machine') cases = [ ('target_os = "windows"', build.equal(build.method('system', HOST_MACHINE), build.string('windows'))), ('target_arch = "x86"', build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86'))), ('target_family = "unix"', build.equal(build.method('system', HOST_MACHINE), build.string('unix'))), ('not(target_arch = "x86")', build.not_(build.equal( build.method('cpu_family', HOST_MACHINE), build.string('x86')))), ('any(target_arch = "x86", target_arch = "x86_64")', build.or_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86')), build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86_64')))), ('any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")', build.or_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86')), build.or_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86_64')), build.equal(build.method('cpu_family', HOST_MACHINE), build.string('aarch64'))))), ('all(target_arch = "x86", target_arch = "x86_64")', build.and_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86')), build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86_64')))), ('all(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")', build.and_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86')), build.and_( build.equal(build.method('cpu_family', HOST_MACHINE), build.string('x86_64')), build.equal(build.method('cpu_family', HOST_MACHINE), build.string('aarch64'))))), ] for data, expected in cases: with self.subTest(): value = cfg.ir_to_meson(cfg.parse(iter(cfg.lexer(data))), build) self.assertEqual(value, expected) class CargoLockTest(unittest.TestCase): def test_cargo_lock(self) -> None: with tempfile.TemporaryDirectory() as tmpdir: with open(os.path.join(tmpdir, 'Cargo.lock'), 'w', encoding='utf-8') as f: f.write(textwrap.dedent('''\ version = 3 [[package]] name = "foo" version = "0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" [[package]] name = "bar" version = "0.1" source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=0.19#23c5599424cc75ec66618891c915d9f490f6e4c2" ''')) wraps = load_wraps(tmpdir, 'subprojects') self.assertEqual(len(wraps), 2) self.assertEqual(wraps[0].name, 'foo-0.1-rs') self.assertEqual(wraps[0].directory, 'foo-0.1') self.assertEqual(wraps[0].type, 'file') self.assertEqual(wraps[0].get('method'), 'cargo') self.assertEqual(wraps[0].get('source_url'), 'https://crates.io/api/v1/crates/foo/0.1/download') self.assertEqual(wraps[0].get('source_hash'), '8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb') self.assertEqual(wraps[1].name, 'bar-0.1-rs') self.assertEqual(wraps[1].directory, 'bar') self.assertEqual(wraps[1].type, 'git') self.assertEqual(wraps[1].get('method'), 'cargo') self.assertEqual(wraps[1].get('url'), 'https://github.com/gtk-rs/gtk-rs-core') self.assertEqual(wraps[1].get('revision'), '23c5599424cc75ec66618891c915d9f490f6e4c2')