diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3226794cc4910a962d7954861858a529751d0f5e..90657bfa79ebd2bf38c8c6cf60d5ac55aa623063 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -112,6 +112,30 @@ build linux arm64: - job: "build synapse arm64" optional: true +build linux meson wraps: + stage: build + image: alpine:latest + tags: [docker] + needs: + - job: "build synapse amd64" + optional: true + variables: + M_ARCH: x86_64 + COVERAGE: "ON" + services: !reference [.build-linux, services] + before_script: + - echo 'https://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories + - apk update && apk add meson git g++ cmake pkgconf openssl openssl-dev make + script: + - meson setup builddir -Dtests=true -Dexamples=true -Ddefault_library=static + - meson compile -C builddir + - MTXCLIENT_SERVER=synapse meson test -C builddir + artifacts: + reports: + junit: builddir/*.xml + paths: + - builddir/*.xml + build-macos: stage: build tags: [macos] diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..23328d65fb19b644076a2098d2ccbda331694a3a --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,31 @@ +spdlog_dep = dependency('spdlog', fallback: ['spdlog', 'spdlog_dep']) + +room_feed = executable('room_feed', + 'room_feed.cpp', + dependencies: [matrix_client_dep], + include_directories : '../tests' + ) + +if meson.get_compiler('cpp').has_header('filesystem') +media_downloader = executable('media_downloader', + 'media_downloader.cpp', + dependencies: [matrix_client_dep], + include_directories : '../tests' + ) +endif + +simple_bot = executable('simple_bot', + 'simple_bot.cpp', + dependencies: [matrix_client_dep], + include_directories : '../tests' + ) +crypto_bot = executable('crypto_bot', + 'crypto_bot.cpp', + dependencies: [matrix_client_dep, spdlog_dep], + include_directories : '../tests' + ) +online_backup_exporter = executable('online_backup_exporter', + 'online_backup_exporter.cpp', + dependencies: [matrix_client_dep], + include_directories : '../tests' + ) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..e2d16607671df50ec7fc33ac533949c56235106d --- /dev/null +++ b/meson.build @@ -0,0 +1,156 @@ +project( + 'mtxclient', + 'cpp', +version : '0.5.1', +meson_version : '>=0.57.0', +license : 'MIT', +default_options : 'cpp_std=c++17' +) + +cmake = import('cmake') + +coeurl_dep = dependency('coeurl', required: true) +thread_dep = dependency('threads', required: true) +openssl_dep = dependency('openssl', version: '>=1.1', required: true) + +json_dep = dependency('nlohmann_json', version: '>=3.2.0', required: true) + +olm_dep = dependency('Olm', method: 'cmake', required: get_option('wrap_mode') == 'nofallback') + +if (not olm_dep.found() + or get_option('wrap_mode') == 'forcefallback' + or 'Olm' in get_option('force_fallback_for')) + olm_options = cmake.subproject_options() + olm_options.add_cmake_defines({ + 'BUILD_SHARED_LIBS': false, + 'OLM_TESTS': false, + }) + if target_machine.system() != 'windows' + olm_options.add_cmake_defines({ + 'CMAKE_C_FLAGS': '-fPIC', + }) + endif + olm_options.set_override_option('werror', 'false') + olm_options.set_override_option('warning_level', '0') + olm_proj = cmake.subproject('Olm', options: olm_options) + olm_dep = olm_proj.dependency('olm') +endif + +deps = [ + coeurl_dep, + thread_dep, + olm_dep, + openssl_dep, + json_dep +] + +inc = include_directories('include') +src = [ + 'lib/crypto/client.cpp', + 'lib/crypto/encoding.cpp', + 'lib/crypto/types.cpp', + 'lib/crypto/utils.cpp', + 'lib/http/client.cpp', + 'lib/log.cpp', + 'lib/structs/common.cpp', + 'lib/structs/errors.cpp', + 'lib/structs/events.cpp', + 'lib/structs/events/account_data/fully_read.cpp', + 'lib/structs/events/aliases.cpp', + 'lib/structs/events/avatar.cpp', + 'lib/structs/events/canonical_alias.cpp', + 'lib/structs/events/collections.cpp', + 'lib/structs/events/common.cpp', + 'lib/structs/events/create.cpp', + 'lib/structs/events/encrypted.cpp', + 'lib/structs/events/encryption.cpp', + 'lib/structs/events/ephemeral/receipt.cpp', + 'lib/structs/events/ephemeral/typing.cpp', + 'lib/structs/events/guest_access.cpp', + 'lib/structs/events/history_visibility.cpp', + 'lib/structs/events/join_rules.cpp', + 'lib/structs/events/member.cpp', + 'lib/structs/events/messages/audio.cpp', + 'lib/structs/events/messages/emote.cpp', + 'lib/structs/events/messages/file.cpp', + 'lib/structs/events/messages/image.cpp', + 'lib/structs/events/messages/notice.cpp', + 'lib/structs/events/messages/text.cpp', + 'lib/structs/events/messages/video.cpp', + 'lib/structs/events/mscs/image_packs.cpp', + 'lib/structs/events/name.cpp', + 'lib/structs/events/nheko_extensions/hidden_events.cpp', + 'lib/structs/events/pinned_events.cpp', + 'lib/structs/events/power_levels.cpp', + 'lib/structs/events/presence.cpp', + 'lib/structs/events/reaction.cpp', + 'lib/structs/events/redaction.cpp', + 'lib/structs/events/spaces.cpp', + 'lib/structs/events/tag.cpp', + 'lib/structs/events/tombstone.cpp', + 'lib/structs/events/topic.cpp', + 'lib/structs/events/unknown.cpp', + 'lib/structs/events/voip.cpp', + 'lib/structs/identifiers.cpp', + 'lib/structs/pushrules.cpp', + 'lib/structs/requests.cpp', + 'lib/structs/responses/common.cpp', + 'lib/structs/responses/create_room.cpp', + 'lib/structs/responses/crypto.cpp', + 'lib/structs/responses/empty.cpp', + 'lib/structs/responses/groups.cpp', + 'lib/structs/responses/login.cpp', + 'lib/structs/responses/media.cpp', + 'lib/structs/responses/messages.cpp', + 'lib/structs/responses/notifications.cpp', + 'lib/structs/responses/profile.cpp', + 'lib/structs/responses/public_rooms.cpp', + 'lib/structs/responses/register.cpp', + 'lib/structs/responses/sync.cpp', + 'lib/structs/responses/turn_server.cpp', + 'lib/structs/responses/version.cpp', + 'lib/structs/responses/well-known.cpp', + 'lib/structs/secret_storage.cpp', + 'lib/structs/user_interactive.cpp', + 'lib/utils.cpp', +] + +matrix_client = library('matrix_client', + src, + dependencies: deps, + include_directories : inc, + install : true) + +matrix_client_dep = declare_dependency( + link_with: matrix_client, + dependencies: deps, + include_directories: inc) + +meson.override_dependency('mtxclient', matrix_client_dep) + +pkg = import('pkgconfig') +pkg.generate(matrix_client, + libraries : [matrix_client], + version : meson.project_version(), + filebase : meson.project_name(), + description : 'Client API library for Matrix.', + url : 'https://github.com/Nheko-Reborn/mtxclient)') + +conf = configuration_data() + +cmake.write_basic_package_version_file( + name: 'MatrixClient', + compatibility: 'AnyNewerVersion', + version: meson.project_version()) +cmake.configure_package_config_file( + name: 'MatrixClient', + input: 'cmake/MatrixClientConfig.cmake.in', + configuration: conf) + +if get_option('examples') + subdir('examples') +endif + +if get_option('tests') + subdir('tests') +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000000000000000000000000000000000..76581a726de6f8c92c2a147599bf4e515de89e56 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('examples', type : 'boolean', value : false) +option('tests', type : 'boolean', value : false) diff --git a/subprojects/Olm.wrap b/subprojects/Olm.wrap new file mode 100644 index 0000000000000000000000000000000000000000..aebfdcf82b3480b3fde282edff732e694086ed08 --- /dev/null +++ b/subprojects/Olm.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory = Olm +url = https://git.matrix.org/git/olm.git +revision = 3.2.6 +buildsystem = cmake + diff --git a/subprojects/coeurl.wrap b/subprojects/coeurl.wrap new file mode 100644 index 0000000000000000000000000000000000000000..9213d30938078c894cb5d2a1fcb053c48d0c6165 --- /dev/null +++ b/subprojects/coeurl.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://nheko.im/nheko-reborn/coeurl.git +revision = head diff --git a/subprojects/gtest.wrap b/subprojects/gtest.wrap new file mode 100644 index 0000000000000000000000000000000000000000..8513793f58e3054a5db6b7a129d46d1dc57ec568 --- /dev/null +++ b/subprojects/gtest.wrap @@ -0,0 +1,15 @@ +[wrap-file] +directory = googletest-release-1.11.0 +source_url = https://github.com/google/googletest/archive/release-1.11.0.zip +source_filename = gtest-1.11.0.zip +source_hash = 353571c2440176ded91c2de6d6cd88ddd41401d14692ec1f99e35d013feda55a +patch_filename = gtest_1.11.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.11.0-1/get_patch +patch_hash = d38c39184384608b08419be52aed1d0f9d9d1b5ed71c0c35e51cccbdddab7084 + +[provide] +gtest = gtest_dep +gtest_main = gtest_main_dep +gmock = gmock_dep +gmock_main = gmock_main_dep + diff --git a/subprojects/nlohmann_json.wrap b/subprojects/nlohmann_json.wrap new file mode 100644 index 0000000000000000000000000000000000000000..f5f41d6182073dde711c3ee7ce4ab684ed4769e8 --- /dev/null +++ b/subprojects/nlohmann_json.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = nlohmann_json-3.9.1 +lead_directory_missing = true +source_url = https://github.com/nlohmann/json/releases/download/v3.9.1/include.zip +source_filename = nlohmann_json-3.9.1.zip +source_hash = 6bea5877b1541d353bd77bdfbdb2696333ae5ed8f9e8cc22df657192218cad91 +patch_url = https://wrapdb.mesonbuild.com/v2/nlohmann_json_3.9.1-1/get_patch +patch_filename = nlohmann_json-3.9.1-1-wrap.zip +patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435 + +[provide] +nlohmann_json = nlohmann_json_dep + diff --git a/subprojects/openssl.wrap b/subprojects/openssl.wrap new file mode 100644 index 0000000000000000000000000000000000000000..4aaaba38d24414f2821a9bfb6820323f5ba716d1 --- /dev/null +++ b/subprojects/openssl.wrap @@ -0,0 +1,14 @@ +[wrap-file] +directory = openssl-1.1.1l +source_url = https://www.openssl.org/source/openssl-1.1.1l.tar.gz +source_filename = openssl-1.1.1l.tar.gz +source_hash = 0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1 +patch_filename = openssl_1.1.1l-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/openssl_1.1.1l-1/get_patch +patch_hash = 670db31580039e06c17f48bcd31e489f453fe72c22006de6d693b9b033f1003a + +[provide] +libcrypto = libcrypto_dep +libssl = libssl_dep +openssl = openssl_dep + diff --git a/subprojects/spdlog.wrap b/subprojects/spdlog.wrap new file mode 100644 index 0000000000000000000000000000000000000000..bfa4995680e9235d45a5a8f0addd951c2a458c93 --- /dev/null +++ b/subprojects/spdlog.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = spdlog-1.8.5 +source_url = https://github.com/gabime/spdlog/archive/v1.8.5.tar.gz +source_filename = v1.8.5.tar.gz +source_hash = 944d0bd7c763ac721398dca2bb0f3b5ed16f67cef36810ede5061f35a543b4b8 +patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.8.5-1/get_patch +patch_filename = spdlog-1.8.5-1-wrap.zip +patch_hash = 3c38f275d5792b1286391102594329e98b17737924b344f98312ab09929b74be + +[provide] +spdlog = spdlog_dep + diff --git a/tests/media_api.cpp b/tests/media_api.cpp index f63435ab97e7869a0e325a126b7cd33b59a044ce..3cf6957d5b47f20f37075080647d65cea133836a 100644 --- a/tests/media_api.cpp +++ b/tests/media_api.cpp @@ -81,7 +81,7 @@ TEST(MediaAPI, UploadAudio) bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) { ASSERT_FALSE(err); - const auto audio = read_file("./fixtures/sound.mp3"); + const auto audio = read_file(fixture_prefix() + "/fixtures/sound.mp3"); bob->upload(audio, "audio/mp3", @@ -112,7 +112,7 @@ TEST(MediaAPI, UploadImage) carl->login("carl", "secret", [carl](const mtx::responses::Login &, RequestErr err) { ASSERT_FALSE(err); - const auto img = read_file("./fixtures/test.jpeg"); + const auto img = read_file(fixture_prefix() + "/fixtures/test.jpeg"); carl->upload(img, "image/jpeg", @@ -157,7 +157,7 @@ TEST(MediaAPI, UploadSVG) carl->login("carl", "secret", [carl](const mtx::responses::Login &, RequestErr err) { ASSERT_FALSE(err); - const auto img = read_file("./fixtures/kiwi.svg"); + const auto img = read_file(fixture_prefix() + "/fixtures/kiwi.svg"); carl->upload(img, "image/svg", diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..766f8f0933ff909070c08ab182c4ed03300fcf49 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,30 @@ +gtest_dep = dependency('gtest', main : true, fallback : ['gtest', 'gtest_main_dep'], required : true) + +client_api = executable('client_api', 'client_api.cpp', dependencies: [matrix_client_dep, gtest_dep]) +media_api = executable('media_api', 'media_api.cpp', dependencies: [matrix_client_dep, gtest_dep]) +e2ee = executable('e2ee', 'e2ee.cpp', dependencies: [matrix_client_dep, gtest_dep]) +utils = executable('utils', 'utils.cpp', dependencies: [matrix_client_dep, gtest_dep]) +pushrules = executable('pushrules', 'pushrules.cpp', dependencies: [matrix_client_dep, gtest_dep]) +connection = executable('connection', 'connection.cpp', dependencies: [matrix_client_dep, gtest_dep]) +identifiers = executable('identifiers', 'identifiers.cpp', dependencies: [matrix_client_dep, gtest_dep]) +events = executable('events', 'events.cpp', dependencies: [matrix_client_dep, gtest_dep]) +messages = executable('messages', 'messages.cpp', dependencies: [matrix_client_dep, gtest_dep]) +responses = executable('responses', 'responses.cpp', dependencies: [matrix_client_dep, gtest_dep]) +requests = executable('requests', 'requests.cpp', dependencies: [matrix_client_dep, gtest_dep]) +errors = executable('errors', 'errors.cpp', dependencies: [matrix_client_dep, gtest_dep]) +crypto = executable('crypto', 'crypto.cpp', dependencies: [matrix_client_dep, gtest_dep]) + +test('connection', connection, protocol: 'gtest', suite: 'network', is_parallel: false) +test('client_api', client_api, protocol: 'gtest', suite: 'network', is_parallel: false, timeout: 300) +test('media_api', media_api, protocol: 'gtest', suite: 'network', is_parallel: false,env: ['FIXTURE_PREFIX='+meson.current_source_dir()]) +test('e2ee', e2ee, protocol: 'gtest', suite: 'network', is_parallel: false) +test('pushrules', pushrules, protocol: 'gtest', suite: 'network', is_parallel: false) + +test('crypto', crypto, protocol: 'gtest', suite: 'nonetwork') +test('errors', errors, protocol: 'gtest', suite: 'nonetwork') +test('requests', requests, protocol: 'gtest', suite: 'nonetwork') +test('responses', responses, protocol: 'gtest', suite: 'nonetwork',env: ['FIXTURE_PREFIX='+meson.current_source_dir()]) +test('messages', messages, protocol: 'gtest', suite: 'nonetwork') +test('events', events, protocol: 'gtest', suite: 'nonetwork') +test('identifiers', identifiers, protocol: 'gtest', suite: 'nonetwork') +test('utils', utils, protocol: 'gtest', suite: 'nonetwork') diff --git a/tests/responses.cpp b/tests/responses.cpp index 9fd1cb3acb6d48df5ab5a15d702e0612d2c3f020..652ade7304c7a25407590fdd2c985d05df16a998 100644 --- a/tests/responses.cpp +++ b/tests/responses.cpp @@ -7,6 +7,8 @@ #include <mtx.hpp> +#include "test_helpers.hpp" + using json = nlohmann::json; using namespace mtx::responses; @@ -323,7 +325,7 @@ TEST(Responses, InvitedRoom) TEST(Responses, Sync) { - std::ifstream file("./fixtures/responses/sync.json"); + std::ifstream file(fixture_prefix() + "/fixtures/responses/sync.json"); json data1; file >> data1; @@ -361,7 +363,7 @@ TEST(Responses, Sync) TEST(Responses, SyncWithEncryption) { - std::ifstream file("./fixtures/responses/sync_with_crypto.json"); + std::ifstream file(fixture_prefix() + "/fixtures/responses/sync_with_crypto.json"); json data; file >> data; diff --git a/tests/test_helpers.hpp b/tests/test_helpers.hpp index b70721c62a7978f15c9de1f91aa1eab60c2d933f..1f9aeeee4f3f2024973b70f3f55425fd891ec4af 100644 --- a/tests/test_helpers.hpp +++ b/tests/test_helpers.hpp @@ -1,6 +1,7 @@ #pragma once #include "gtest/gtest.h" +#include <cstdlib> #include <iostream> #include <limits> #include <random> @@ -90,3 +91,14 @@ get_event_ids(const std::vector<Collection> &events) return ids; } + +inline std::string +fixture_prefix() +{ + auto var = std::getenv("FIXTURE_PREFIX"); + + if (var) + return var; + else + return "."; +}