# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of libnvme.
# Copyright (c) 2021 Dell Inc.
#
# Authors: Martin Belanger <Martin.Belanger@dell.com>

python3_prog = find_program('python3', required: false)
if python3_prog.found()
    test(
        'libnvme - check-public-symbols',
        python3_prog,
        args: [
            files('../tools/check-public-symbols.py'),
            meson.project_source_root() / 'libnvme',
        ],
    )
    _ld_args = ['--ld', nvme_ld, '--ld', accessors_ld, '--ld', attr_accessors_ld]
    if want_fabrics
        _ld_args += ['--ld', nvmf_ld, '--ld', nvmf_accessors_ld]
    endif
    _hdr_args = []
    foreach hdr : headers + generated_headers
        _hdr_args += ['--header', meson.project_source_root() / 'libnvme' / 'src' / hdr]
    endforeach
    test(
        'libnvme - check-public-headers',
        python3_prog,
        args: [files('../tools/check-public-headers.py')] + _ld_args + _hdr_args,
    )
endif

# These tests all require interaction with a real NVMe device, so we don't
# define as meson unit-tests, and therefore get run as part of the 'test'
# target. However, they're available for developer use, when hardware is
# available.
main = executable(
    'main-test',
    ['test.c'],
    dependencies: [
        config_dep,
        ccan_dep,
        libnvme_test_dep,
    ],
)

if cxx_available
    cpp = executable(
        'test-cpp',
        ['cpp.cc'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - cpp-dump', cpp)

    misc = executable(
        'test-misc',
        ['misc.cc'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )
    test('libnvme - cpp-misc', misc)

endif

if host_system != 'windows'
    register = executable(
        'test-register',
        ['register.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    zns = executable(
        'test-zns',
        ['zns.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )
endif # host_system != 'windows'

if want_mi
    mi = executable(
        'test-mi',
        ['mi.c', 'utils.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - mi', mi)

    mi_mctp = executable(
        'test-mi-mctp',
        ['mi-mctp.c', 'utils.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - mi-mctp', mi_mctp)
endif

uuid = executable(
    'test-uuid',
    ['uuid.c'],
    dependencies: [
        config_dep,
        ccan_dep,
        libnvme_dep,
    ],
)

test('libnvme - uuid', uuid)

if host_system == 'linux' and (not is_static)
    mem = executable(
        'test-mem',
        ['mem.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
            dl_dep,
        ],
    )

    test('libnvme - mem', mem)
endif

tree = executable(
    'test-tree',
    ['tree.c'],
    dependencies: [
        config_dep,
        ccan_dep,
        libnvme_test_dep,
    ],
)

test('libnvme - tree', tree)

if want_fabrics
    test_tid = executable(
        'test-tid',
        ['test-tid.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - tid', test_tid)

    registry = executable(
        'test-registry',
        ['registry.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - registry', registry)

    exclusion = executable(
        'test-exclusion',
        ['exclusion.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - exclusion', exclusion)

    config_ini = executable(
        'test-config-ini',
        ['config-ini.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            shared_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - config-ini', config_ini)

    config_api = executable(
        'test-config-api',
        ['config-api.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - config-api', config_api)

    config_emit = executable(
        'test-config-emit',
        ['config-emit.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - config-emit', config_emit)

    uriparser = executable(
        'test-uriparser',
        ['uriparser.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - uriparser', uriparser)

    test_fabrics = executable(
        'test-fabrics',
        ['test-fabrics.c'],
        # -fgnu89-inline: '#define static' (used to expose static helpers
        # for unit testing) turns 'static inline' into plain 'inline'.
        # Under C99, plain 'inline' has external linkage and may require an
        # external symbol definition that doesn't exist for header-only
        # inline functions.  GNU89 semantics treat it as an inlining hint
        # only, avoiding the linker failure in -static builds.
        c_args: ['-fgnu89-inline'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )

    test('libnvme - fabrics', test_fabrics)

    psk = executable(
        'test-psk',
        ['psk.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_dep,
        ],
    )

    test('libnvme - psk', psk)

    if openssl_dep.found()
        raw_secret = executable(
            'test-raw-secret',
            ['raw-secret.c'],
            dependencies: [
                config_dep,
                ccan_dep,
                libnvme_dep,
            ],
        )

        test('libnvme - raw-secret', raw_secret)
    endif
endif

if want_fabrics
    mock_ifaddrs = library(
        'mock-ifaddrs',
        ['mock-ifaddrs.c', ],
    )

    # See comment in test/ioctl/meson.build explaining how LD_PRELOAD is used
    mock_ifaddrs_env = environment()
    mock_ifaddrs_env.append('LD_PRELOAD', mock_ifaddrs.full_path())
    mock_ifaddrs_env.set('ASAN_OPTIONS', 'verify_asan_link_order=0')

    tree_fabrics = executable(
        'tree-fabrics',
        ['tree-fabrics.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
        link_with: mock_ifaddrs,
    )

    test('libnvme - tree-fabrics', tree_fabrics, env: mock_ifaddrs_env)

    test_util = executable(
        'test-util',
        ['test-util.c'],
        dependencies: [
            config_dep,
            ccan_dep,
            libnvme_test_dep,
        ],
    )
    test('libnvme - util', test_util)
endif

if want_ioctl_tests
    subdir('ioctl')
endif

if host_system == 'linux'
    subdir('sysfs')
    if want_fabrics
        subdir('nbft')
    endif

    if openssl_dep.found()
        hkdf_add1 = executable(
            'hkdf_add1',
            ['hkdf_add1.c'],
            dependencies: openssl_dep,
        )
    endif
endif

foreach hdr : [
    'endian',
    'fabrics',
    'ioctl',
    'lib',
    'lib-types',
    'mi',
    'nbft',
    'nvme-cmds',
    'nvme-cmds-base',
    'nvme-cmds-fabrics',
    'nvme-cmds-mi',
    'nvme-cmds-nvm',
    'nvme-cmds-zns',
    'nvme-types',
    'nvme-types-base',
    'nvme-types-fabrics',
    'nvme-types-mi',
    'nvme-types-nbft',
    'nvme-types-nvm',
    'nvme-types-slm',
    'nvme-types-zns',
    'scan',
    'tree',
    'util',
]
    hdr_conf = configuration_data()
    hdr_conf.set('HDR', hdr)
    src = configure_file(
        input: 'test-header.c.in',
        output: 'test-header-' + hdr + '.c',
        configuration: hdr_conf,
    )
    exe = executable(
        'test-header-' + hdr,
        src,
        dependencies: [libnvme_dep],
    )
    test('libnvme - header/' + hdr, exe)
endforeach
