From 9fecc8301aa185d9ae552fc0faab8cb599eff5a2 Mon Sep 17 00:00:00 2001 From: Romain Thomas Date: Sat, 15 Jul 2023 06:34:59 +0200 Subject: [PATCH] Use cache for the iOS ci and improve testing --- .github/workflows/ios.yml | 35 +++++++++-- .github/workflows/osx.yml | 2 +- .github/workflows/pr.yml | 4 +- .github/workflows/windows-all.yml | 5 +- .github/workflows/windows-quick.yml | 5 +- api/python/src/ELF/objects/pyBinary.cpp | 12 +++- include/LIEF/ELF/Binary.hpp | 11 ++-- scripts/docker/run_linux_test.sh | 2 +- src/ELF/Binary.cpp | 13 +--- src/ELF/Builder.tcc | 2 +- tests/dl_samples.py | 36 +++++++++-- tests/elf/test_builder.py | 4 +- tests/elf/test_elf_config.py | 11 ++++ tests/macho/test_generic.py | 18 +++++- tests/requirements.txt | 3 + tests/unittests/CMakeLists.txt | 8 ++- tests/unittests/test_binarystream.cpp | 82 +++++++++++++++++++++++++ tests/unittests/test_enums.cpp | 60 ++++++++++++++++++ tests/unittests/test_hash.cpp | 58 +++++++++++++++++ tests/unittests/test_utils.cpp | 43 +++++++++++++ tests/unittests/utils.cpp | 39 ++++++++++++ tests/unittests/utils.hpp | 24 ++++++++ tests/utils.py | 2 +- 23 files changed, 434 insertions(+), 45 deletions(-) create mode 100644 tests/requirements.txt create mode 100644 tests/unittests/test_binarystream.cpp create mode 100644 tests/unittests/test_enums.cpp create mode 100644 tests/unittests/test_hash.cpp create mode 100644 tests/unittests/test_utils.cpp create mode 100644 tests/unittests/utils.cpp create mode 100644 tests/unittests/utils.hpp diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index e5c49a00..5879a51e 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -5,7 +5,7 @@ env: python-version: '3.10' jobs: - osx-sdk: + ios-sdk: runs-on: macos-11.0 steps: - uses: actions/checkout@v3 @@ -31,14 +31,14 @@ jobs: - name: ccache cache files uses: actions/cache@v3 with: - path: ~/.ccache + path: ${{ runner.temp }}/.ccache key: ios-${{ runner.os }}-${{ steps.get-date.outputs.date }} restore-keys: | - ios-${{ runner.os }}- + ios-${{ runner.os }} - name: Build iOS SDK shell: bash env: - CCACHE_DIR: ~/.ccache + CCACHE_DIR: ${{ runner.temp }}/.ccache CCACHE_MAXSIZE: 10.0G CCACHE_CPP2: 1 CCACHE_COMPRESS: 1 @@ -50,14 +50,37 @@ jobs: name: ios-sdk path: build/*.tar.gz retention-days: 3 + deploy: + runs-on: ubuntu-latest + if: ${{ always() }} + needs: ios-sdk + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + path: ${{ runner.temp }}/artifacts + - name: Display artifacts + run: ls -R + working-directory: ${{ runner.temp }}/artifacts - name: Deploy env: LIEF_S3_KEY: ${{ secrets.LIEF_S3_KEY }} LIEF_S3_SECRET: ${{ secrets.LIEF_S3_SECRET }} shell: bash run: | - python -m pip install --upgrade requests mako boto3 tomli - python .github/deploy.py build/ + docker run --rm \ + -v $GITHUB_WORKSPACE:/src \ + -v $RUNNER_TEMP:/runner_tmp \ + -e GITHUB_ACTIONS="true" \ + -e GITHUB_WORKSPACE=$GITHUB_WORKSPACE \ + -e GITHUB_REF=$GITHUB_REF \ + -e GITHUB_REPOSITORY=$GITHUB_REPOSITORY \ + -e LIEF_S3_KEY=$LIEF_S3_KEY \ + -e LIEF_S3_SECRET=$LIEF_S3_SECRET \ + liefproject/deploy python3 /src/.github/deploy.py /runner_tmp/artifacts diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 64c8ba04..dcd67160 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -105,7 +105,7 @@ jobs: CCACHE_CPP2: 1 CCACHE_COMPRESS: 1 run: | - python -m pip install pytest requests + python -m pip install -r tests/requirements.txt python tests/dl_samples.py ${LIEF_SAMPLES_DIR} cd api/python PYLIEF_CONF=${GITHUB_WORKSPACE}/scripts/osx/osx-testing-x64.toml \ diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 21fc1135..e98fc8cf 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -26,7 +26,7 @@ jobs: LIEF_SAMPLES_DIR: "/tmp/samples" BUILD_DIR: "/tmp/lief-build" run: | - python -m pip install pytest requests + python -m pip install -r tests/requirements.txt python tests/dl_samples.py ${LIEF_SAMPLES_DIR} cd api/python PYLIEF_CONF=${GITHUB_WORKSPACE}/scripts/osx/osx-testing-x64.toml \ @@ -78,7 +78,7 @@ jobs: echo ("PYLIEF_CONF=" + $env:GITHUB_WORKSPACE + "/scripts/windows/py-x64-test.toml") >> $env:GITHUB_ENV - name: Build Python ${{ env.python-win-version }} run: | - python -m pip install pytest requests + python -m pip install -r tests/requirements.txt python tests/dl_samples.py %LIEF_SAMPLES_DIR% cd api/python python ./setup.py build ^ diff --git a/.github/workflows/windows-all.yml b/.github/workflows/windows-all.yml index a99cf1e6..f148b8e0 100644 --- a/.github/workflows/windows-all.yml +++ b/.github/workflows/windows-all.yml @@ -130,7 +130,7 @@ jobs: echo ("BUILD_DIR=" + $env:RUNNER_TEMP + "/lief-build") >> $env:GITHUB_ENV - name: Build Python ${{ env.python-test-version }} run: | - python -m pip install pytest requests + python -m pip install -r tests/requirements.txt python tests/dl_samples.py %LIEF_SAMPLES_DIR% cd api/python python ./setup.py build ^ @@ -172,8 +172,7 @@ jobs: run: | choco install ninja choco install sccache - python -m pip install --upgrade pip setuptools - python -m pip install wheel mako + python -m pip install --upgrade pip setuptools wheel - uses: ilammy/msvc-dev-cmd@v1 with: toolset: "14.16" diff --git a/.github/workflows/windows-quick.yml b/.github/workflows/windows-quick.yml index 4831d47e..ad58c9b4 100644 --- a/.github/workflows/windows-quick.yml +++ b/.github/workflows/windows-quick.yml @@ -34,8 +34,7 @@ jobs: run: | choco install ninja choco install sccache - python -m pip install --upgrade pip setuptools - python -m pip install wheel mako + python -m pip install --upgrade pip setuptools wheel - uses: ilammy/msvc-dev-cmd@v1 with: toolset: "14.16" @@ -64,7 +63,7 @@ jobs: shell: cmd - name: Build Python ${{ env.python-version }} run: | - python -m pip install pytest requests + python -m pip install -r tests/requirements.txt python tests/dl_samples.py %LIEF_SAMPLES_DIR% python -m pip -vv install api/python shell: cmd diff --git a/api/python/src/ELF/objects/pyBinary.cpp b/api/python/src/ELF/objects/pyBinary.cpp index 0f226982..c9b8f328 100644 --- a/api/python/src/ELF/objects/pyBinary.cpp +++ b/api/python/src/ELF/objects/pyBinary.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "nanobind/extra/memoryview.hpp" #include "ELF/pyELF.hpp" @@ -692,8 +693,15 @@ void create(nb::module_& m) { "True if data are appended to the end of the binary"_doc) .def_prop_rw("overlay", - nb::overload_cast<>(&Binary::overlay, nb::const_), - nb::overload_cast(&Binary::overlay), + [] (const Binary& self) { + const span overlay = self.overlay(); + return nb::memoryview::from_memory(overlay.data(), overlay.size()); + }, + [] (Binary& self, nb::bytes& bytes) { + const auto* ptr = reinterpret_cast(bytes.c_str()); + std::vector buffer(ptr, ptr + bytes.size()); + self.overlay(std::move(buffer)); + }, "Overlay data that are not a part of the ELF format"_doc) .def("relocate_phdr_table", diff --git a/include/LIEF/ELF/Binary.hpp b/include/LIEF/ELF/Binary.hpp index f1542075..89503ed1 100644 --- a/include/LIEF/ELF/Binary.hpp +++ b/include/LIEF/ELF/Binary.hpp @@ -63,7 +63,6 @@ class LIEF_API Binary : public LIEF::Binary { public: using string_list_t = std::vector; - using overlay_t = std::vector; //! Internal container for storing notes using notes_t = std::vector>; @@ -743,13 +742,15 @@ class LIEF_API Binary : public LIEF::Binary { uint64_t eof_offset() const; //! True if data are present at the end of the binary - bool has_overlay() const; + bool has_overlay() const { + return !overlay_.empty(); + } //! Overlay data (if any) - const overlay_t& overlay() const; + span overlay() const; //! Function to set the overlay - void overlay(overlay_t overlay); + void overlay(std::vector overlay); //! Force relocating the segments table in a specific way. //! @@ -873,7 +874,7 @@ class LIEF_API Binary : public LIEF::Binary { phdr_relocation_info_t phdr_reloc_info_; std::string interpreter_; - overlay_t overlay_; + std::vector overlay_; std::unique_ptr sizing_info_; }; diff --git a/scripts/docker/run_linux_test.sh b/scripts/docker/run_linux_test.sh index 7ea2e391..bd24648f 100644 --- a/scripts/docker/run_linux_test.sh +++ b/scripts/docker/run_linux_test.sh @@ -7,7 +7,7 @@ export LDFLAGS='-Wl,--gc-sections' BUILD_DIR=/tmp/lief-build -$PYTHON_BINARY -m pip install pytest requests +$PYTHON_BINARY -m pip install -r /src/tests/requirements.txt mkdir -p ${LIEF_SAMPLES_DIR} diff --git a/src/ELF/Binary.cpp b/src/ELF/Binary.cpp index aaa05e1b..be73da02 100644 --- a/src/ELF/Binary.cpp +++ b/src/ELF/Binary.cpp @@ -1882,7 +1882,6 @@ Section* Binary::get(ELF_SECTION_TYPES type) { return const_cast(static_cast(this)->get(type)); } - bool Binary::has(SEGMENT_TYPES type) const { return get(type) != nullptr; } @@ -1895,8 +1894,6 @@ bool Binary::has(ELF_SECTION_TYPES type) const { return get(type) != nullptr; } - - void Binary::permute_dynamic_symbols(const std::vector& permutation) { std::set done; for (size_t i = 0; i < permutation.size(); ++i) { @@ -2739,15 +2736,11 @@ uint64_t Binary::eof_offset() const { } -bool Binary::has_overlay() const { - return !overlay_.empty(); -} - -const Binary::overlay_t& Binary::overlay() const { +span Binary::overlay() const { return overlay_; } -void Binary::overlay(Binary::overlay_t overlay) { +void Binary::overlay(std::vector overlay) { overlay_ = std::move(overlay); } @@ -3538,7 +3531,5 @@ std::ostream& Binary::print(std::ostream& os) const { Binary::~Binary() = default; - - } } diff --git a/src/ELF/Builder.tcc b/src/ELF/Builder.tcc index ff737481..38691327 100644 --- a/src/ELF/Builder.tcc +++ b/src/ELF/Builder.tcc @@ -1759,7 +1759,7 @@ ok_error_t Builder::build_overlay() { if (binary_->overlay_.empty()) { return ok(); } - const Binary::overlay_t& overlay = binary_->overlay(); + const span overlay = binary_->overlay(); const uint64_t last_offset = binary_->eof_offset(); if (last_offset > 0) { diff --git a/tests/dl_samples.py b/tests/dl_samples.py index 88ba14b5..b8c78610 100644 --- a/tests/dl_samples.py +++ b/tests/dl_samples.py @@ -3,6 +3,8 @@ import pathlib import sys import zipfile import os +import time +import progressbar URL = "https://data.romainthomas.fr/lief_tests.zip" DIR_ENV = os.getenv("LIEF_SAMPLES_DIR", None) @@ -18,6 +20,16 @@ else: DST.mkdir(exist_ok=True) +def hsize(num, suffix="B"): + for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: + if abs(num) < 1024.0: + return f"{num:3.1f}{unit}{suffix}" + num /= 1024.0 + return f"{num:.1f}Yi{suffix}" + +def mb(value: int) -> int: + return round(value / (1024 * 1024), 3) + def download(): out = DST / "samples.zip" if out.is_file(): @@ -26,15 +38,31 @@ def download(): print("Downloading {} in {} ...".format(URL, out)) with requests.get(URL, stream=True) as r: r.raise_for_status() + size = int(r.headers['Content-Length'].strip()) + pbar = progressbar.ProgressBar(maxval=mb(size)).start() + print(f"Total size: {hsize(size)}") + current_len = 0 with open(out, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): f.write(chunk) + current_len += len(chunk) + pbar.update(mb(current_len)) + print("done!") return out -zip_samples = download() +def main(): + zip_samples = download() -with zipfile.ZipFile(zip_samples) as zfile: - zfile.extractall(path=DST) + with zipfile.ZipFile(zip_samples) as zfile: + zfile.extractall(path=DST) -print("Files extracted in {}".format(DST)) + print("Files extracted in {}".format(DST)) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("Aborted!") + (DST / "samples.zip").unlink(missing_ok=True) + sys.exit(1) diff --git a/tests/elf/test_builder.py b/tests/elf/test_builder.py index 223e5417..658e1360 100644 --- a/tests/elf/test_builder.py +++ b/tests/elf/test_builder.py @@ -7,9 +7,10 @@ import stat import subprocess import sys import pytest +from pathlib import Path from subprocess import Popen -from utils import is_linux, glibc_version +from utils import is_linux, glibc_version, get_sample SAMPLE_DIR = pathlib.Path(os.getenv("LIEF_SAMPLES_DIR", "")) @@ -240,4 +241,3 @@ def test_go_files(tmp_path): stdout = proc.stdout.read() proc.poll() assert "done" in normalize(stdout) - diff --git a/tests/elf/test_elf_config.py b/tests/elf/test_elf_config.py index 5c08fee7..323e1628 100644 --- a/tests/elf/test_elf_config.py +++ b/tests/elf/test_elf_config.py @@ -61,3 +61,14 @@ def test_config_3(): assert len(elf.static_symbols) > 0 assert len(elf.symbols_version) == 0 assert len(elf.notes) == 0 + +def test_config_no_overlay(): + config = lief.ELF.ParserConfig() + + config.parse_overlay = False + fpath = get_sample("ELF/batch-x86-64/test.dart.bin") + assert len(lief.parse(fpath).overlay) > 0 + elf = lief.ELF.parse(fpath) + assert elf.has_overlay + elf = lief.ELF.parse(fpath, config) + assert len(elf.overlay) == 0 diff --git a/tests/macho/test_generic.py b/tests/macho/test_generic.py index 660daf34..8bae7caf 100644 --- a/tests/macho/test_generic.py +++ b/tests/macho/test_generic.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import lief from utils import get_sample +import hashlib def test_function_starts(): dd = lief.parse(get_sample('MachO/MachO64_x86-64_binary_dd.bin')) @@ -19,8 +20,8 @@ def test_function_starts(): ] assert dd.function_starts.data_offset == 21168 - assert dd.function_starts.data_size == 48 - text_segment = list(filter(lambda e : e.name == "__TEXT", dd.segments))[0] + assert dd.function_starts.data_size == 48 + text_segment = list(filter(lambda e: e.name == "__TEXT", dd.segments))[0] functions_dd = map(text_segment.virtual_address .__add__, dd.function_starts.functions) assert functions == list(functions_dd) @@ -262,3 +263,16 @@ def test_issue_728(): new_segment = parsed.add(segment) assert new_segment.virtual_size == parsed.page_size +def test_twolevel_hints(): + sample = lief.MachO.parse(get_sample("MachO/ios1-expr.bin"))[0] + tw_hints: lief.MachO.TwoLevelHints = sample[lief.MachO.LOAD_COMMAND_TYPES.TWOLEVEL_HINTS] + assert tw_hints is not None + print(tw_hints) + hints = tw_hints.hints + assert len(hints) == 26 + print(hints[0]) + assert sum(hints) == 10854400 + assert hints[0] == 54528 + assert hashlib.sha256(tw_hints.data).hexdigest() == "e44cef3a83eb89954557a9ad2a36ebf4794ce0385da5a39381fdadc3e6037beb" + assert tw_hints.command_offset == 1552 + print(lief.to_json(tw_hints)) diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 00000000..6c2916cc --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,3 @@ +pytest +requests +progressbar2 diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 3a9e3e9b..dda2a507 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -12,7 +12,13 @@ FetchContent_MakeAvailable(Catch2) add_executable(unittests "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/test_iterators.cpp") + "${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/test_iterators.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/test_enums.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/test_utils.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/test_hash.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/test_binarystream.cpp" +) set_target_properties(unittests PROPERTIES CXX_STANDARD 17 diff --git a/tests/unittests/test_binarystream.cpp b/tests/unittests/test_binarystream.cpp new file mode 100644 index 00000000..3fda2eed --- /dev/null +++ b/tests/unittests/test_binarystream.cpp @@ -0,0 +1,82 @@ +/* Copyright 2017 - 2023 R. Thomas + * Copyright 2017 - 2023 Quarkslab + * + * 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. + */ +#include +#include + +#include "utils.hpp" + +#include +#include +#include +#include +#include + +using namespace LIEF; + +TEST_CASE("lief.test.binarystream", "[lief][test][binarystream]") { + SECTION("MemoryStream") { + std::vector buffer = { + 0x00, 0x10, 0x23, 0x40 + }; + const auto buffer_addr = reinterpret_cast(buffer.data()); + + MemoryStream stream(buffer_addr, buffer.size()); + REQUIRE(stream.base_address() == buffer_addr); + REQUIRE(stream.binary() == nullptr); + REQUIRE(stream.pos() == 0); + REQUIRE(stream.size() == buffer.size()); + REQUIRE(stream.end() == reinterpret_cast(buffer.data() + buffer.size())); + REQUIRE(stream.peek() == 0x00); + REQUIRE(stream.peek(1) == 0x10); + REQUIRE(stream.peek(3) == 0x40); + REQUIRE(MemoryStream::classof(stream)); + } + + SECTION("FileStream") { + const std::string& filepath = test::get_sample("PE", "PE64_x86-64_library_libLIEF.dll"); + + auto fstream = FileStream::from_file(filepath); + REQUIRE(fstream); + FileStream& fs = *fstream; + REQUIRE(FileStream::classof(fs)); + + std::vector buffer; + fs.peek_data(buffer, std::numeric_limits::max(), 4); + REQUIRE(buffer.empty()); + + fs.peek_data(buffer, 0, 4); + REQUIRE(!buffer.empty()); + REQUIRE(buffer.size() == 4); + } + + SECTION("VectorStream") { + std::vector buffer{1, 2, 3}; + VectorStream vs(buffer); + REQUIRE(VectorStream::classof(vs)); + + REQUIRE(vs.p() == vs.content().data()); + REQUIRE(vs.start() == vs.p()); + REQUIRE(vs.end() == vs.content().data() + vs.content().size()); + REQUIRE(static_cast(vs).p() == static_cast(vs).p()); + REQUIRE(static_cast(vs).end() == static_cast(vs).end()); + REQUIRE(static_cast(vs).start() == static_cast(vs).start()); + vs.read(); + + REQUIRE(vs.p() != vs.content().data()); + REQUIRE(vs.start() != vs.p()); + } + +} diff --git a/tests/unittests/test_enums.cpp b/tests/unittests/test_enums.cpp new file mode 100644 index 00000000..e553294a --- /dev/null +++ b/tests/unittests/test_enums.cpp @@ -0,0 +1,60 @@ +/* Copyright 2017 - 2023 R. Thomas + * Copyright 2017 - 2023 Quarkslab + * + * 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. + */ +#include +#include +#include + +enum class TEST_ENUM: uint32_t { + None = 0, + A = 1 << 2, + B = 1 << 5, + + A_or_B = A | B, + A_and_B = A & B, + not_A = ~A, +}; + +ENABLE_BITMASK_OPERATORS(TEST_ENUM); + +TEST_CASE("lief.test.enums_bitmask", "[lief][test][enums_bitmask]") { + + SECTION("operator|") { + REQUIRE((TEST_ENUM::A | TEST_ENUM::B) == TEST_ENUM::A_or_B); + } + + SECTION("operator&") { + REQUIRE((TEST_ENUM::A & TEST_ENUM::B) == TEST_ENUM::A_and_B); + } + + SECTION("operator~") { + REQUIRE(~TEST_ENUM::A == TEST_ENUM::not_A); + } + + SECTION("operator|=") { + TEST_ENUM value = TEST_ENUM::A; + REQUIRE((value |= TEST_ENUM::B) == TEST_ENUM::A_or_B); + } + + SECTION("operator&=") { + TEST_ENUM value = TEST_ENUM::A; + REQUIRE((value &= TEST_ENUM::B) == TEST_ENUM::A_and_B); + } + + SECTION("bool") { + REQUIRE(is_true(TEST_ENUM::A)); + REQUIRE(!is_true(TEST_ENUM::None)); + } +} diff --git a/tests/unittests/test_hash.cpp b/tests/unittests/test_hash.cpp new file mode 100644 index 00000000..77d1681c --- /dev/null +++ b/tests/unittests/test_hash.cpp @@ -0,0 +1,58 @@ +/* Copyright 2017 - 2023 R. Thomas + * Copyright 2017 - 2023 Quarkslab + * + * 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. + */ +#include +#include +#include +#include + +using namespace LIEF; + +TEST_CASE("lief.test.hash", "[lief][test][hash]") { + + SECTION("std::vector") { + std::vector buffer_1 = {1, 2, 3, 4}; + std::vector buffer_2 = {1, 2, 3, 4}; + REQUIRE(hash(buffer_1) == hash(buffer_2)); + } + + SECTION("span") { + std::vector buffer_1 = {1, 2, 3, 4}; + std::vector buffer_2 = {1, 2, 3, 4}; + + const span S1 = buffer_1; + const span S2 = buffer_2; + + REQUIRE(hash(S1) == hash(S2)); + } + + SECTION("LIEF::Object") { + ELF::Section S1(".hello"); + ELF::Section S2(".hello"); + + REQUIRE(hash(S1) == hash(S2)); + } + + + SECTION("LIEF::Hash::pair") { + Hash H1(0x123); + Hash H2(0x123); + + auto P1 = std::make_pair(1, 2); + auto P2 = std::make_pair(1, 2); + + REQUIRE(H1.process(P1).value() == H2.process(P2).value()); + } +} diff --git a/tests/unittests/test_utils.cpp b/tests/unittests/test_utils.cpp new file mode 100644 index 00000000..b8fe9153 --- /dev/null +++ b/tests/unittests/test_utils.cpp @@ -0,0 +1,43 @@ +/* Copyright 2017 - 2023 R. Thomas + * Copyright 2017 - 2023 Quarkslab + * + * 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. + */ +#include +#include +#include +using namespace LIEF; + +TEST_CASE("lief.test.utils", "[lief][test][utils]") { + + SECTION("align") { + REQUIRE(align(30, 0) == 30); + REQUIRE(align(3, 8) == 8); + REQUIRE(align(15, 16) == 16); + REQUIRE(align(29, 16) == 32); + } + + SECTION("round") { + REQUIRE(round(1) == 1); + REQUIRE(round(0x99) == 0x100); + REQUIRE(round(0x10000) == 0x10000); + REQUIRE(round(std::numeric_limits::max() - 1) == 0x10000); + } + + SECTION("size_literal") { + REQUIRE(2_KB == 2048); + REQUIRE(3_MB == 3072_KB); + REQUIRE(4_GB == 4096_MB); + } + +} diff --git a/tests/unittests/utils.cpp b/tests/unittests/utils.cpp new file mode 100644 index 00000000..d9a1c427 --- /dev/null +++ b/tests/unittests/utils.cpp @@ -0,0 +1,39 @@ +#include "utils.hpp" +#include +#include + +namespace fs = std::filesystem; + +using namespace std::literals::string_literals; + +namespace LIEF::test { +std::string get_sample_dir() { + if (char* dir = std::getenv("LIEF_SAMPLES_DIR")) { + fs::path path_dir(dir); + if (fs::is_directory(path_dir)) { + return fs::absolute(path_dir); + } + logging::log(logging::LOG_ERR, "'"s + path_dir.c_str() + "' is" + " not a valid directory"); + std::exit(1); + } + logging::log(logging::LOG_ERR, "LIEF_SAMPLES_DIR not set!"); + std::exit(1); +} + +std::string get_sample(const std::string& name) { + fs::path sample_dir = get_sample_dir(); + fs::path fullpath = sample_dir / name; + if (!fs::exists(fullpath) || !fs::is_regular_file(fullpath)) { + logging::log(logging::LOG_ERR, "'"s + fullpath.c_str() + "' is" + " does not exist"); + std::exit(1); + } + return fs::absolute(fullpath); +} + +std::string get_sample(const std::string& format, const std::string& name) { + return get_sample(fs::path(format) / name); +} + +} diff --git a/tests/unittests/utils.hpp b/tests/unittests/utils.hpp new file mode 100644 index 00000000..ea97a5fa --- /dev/null +++ b/tests/unittests/utils.hpp @@ -0,0 +1,24 @@ +/* Copyright 2017 - 2023 R. Thomas + * Copyright 2017 - 2023 Quarkslab + * + * 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. + */ +#ifndef LIEF_TEST_UTILS_H +#define LIEF_TEST_UTILS_H +#include +namespace LIEF::test { +std::string get_sample_dir(); +std::string get_sample(const std::string& name); +std::string get_sample(const std::string& format, const std::string& name); +} +#endif diff --git a/tests/utils.py b/tests/utils.py index afc4ef91..3aae09d4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -19,7 +19,7 @@ def import_from_file(module_name: str, file_path: pathlib.Path): def lief_samples_dir() -> str: dir = os.getenv("LIEF_SAMPLES_DIR", None) if dir is None: - print("LIEF_SAMPES_DIR is not set", file=sys.stderr) + print("LIEF_SAMPLES_DIR is not set", file=sys.stderr) sys.exit(1) if not os.path.isdir(dir): print("{} is not a valid directory".format(dir), file=sys.stderr)