Skip to content

Commit

Permalink
Merge pull request #577 from IENT/feature/addGoogleTestAsSubmodule
Browse files Browse the repository at this point in the history
Added google test and moved tests.
  • Loading branch information
ChristianFeldmann authored Jul 31, 2024
2 parents 6aadaea + 1fc6743 commit 8e13a10
Show file tree
Hide file tree
Showing 96 changed files with 4,126 additions and 3,079 deletions.
28 changes: 18 additions & 10 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
QMAKE_COMMAND: qmake6
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: git fetch --prune --unshallow
- name: Install Linux packages
run: |
Expand All @@ -32,7 +34,8 @@ jobs:
cd build
${{matrix.QMAKE_COMMAND}} CONFIG+=UNITTESTS ..
make -j$(nproc)
make check
- name: Run Unittests
run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest
build-mac-native:
runs-on: ${{ matrix.os }}
strategy:
Expand All @@ -42,6 +45,8 @@ jobs:
- os: macos-14
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: git fetch --prune --unshallow
- name: Install packages
run: |
Expand All @@ -53,7 +58,8 @@ jobs:
cd build
qmake6 CONFIG+=UNITTESTS ..
make -j $(sysctl -n hw.logicalcpu)
make check
- name: Run Unittests
run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest
build-unix:
runs-on: ${{ matrix.os }}
strategy:
Expand All @@ -79,6 +85,8 @@ jobs:
CPU_COUNT_COMMAND: sysctl -n hw.logicalcpu
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: git fetch --prune --unshallow
- name: Install Qt base
run: |
Expand All @@ -104,15 +112,16 @@ jobs:
curl -L https://github.com/ChristianFeldmann/libde265/releases/download/v1.1/${{matrix.LIBDE265_REMOTE}} -o ${{matrix.LIBDE265_LOCAL}}
curl -L https://raw.githubusercontent.com/ChristianFeldmann/libde265/master/COPYING -o libde265License.txt
shell: bash
- name: Build Linux/Mac
- name: Build
run: |
cd $GITHUB_WORKSPACE
export PATH=$GITHUB_WORKSPACE/../../YUViewQt/YUViewQt/Qt/bin:$PATH
mkdir build
cd build
qmake CONFIG+=UNITTESTS ..
make -j $(${{matrix.CPU_COUNT_COMMAND}})
make check
- name: Run Unittests
run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest
- name: Build App (Mac)
run: |
macdeployqt build/YUViewApp/YUView.app -always-overwrite -verbose=2
Expand All @@ -122,7 +131,7 @@ jobs:
zip -r ${{matrix.ARTIFACT_NAME}} YUView.app/
mkdir $GITHUB_WORKSPACE/artifacts
cp ${{matrix.ARTIFACT_NAME}} $GITHUB_WORKSPACE/artifacts/
if: matrix.os == 'macos-11' || matrix.os == 'macos-12'
if: matrix.os == 'macos-12' || matrix.os == 'macos-14'
- name: Build Appimage (Linux)
run: |
cd build
Expand Down Expand Up @@ -157,6 +166,8 @@ jobs:
QT_FILE: qtBase_6.7.2_win2019.zip
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ilammy/msvc-dev-cmd@v1
- run: git fetch --prune --unshallow
- name: Install Qt base
Expand Down Expand Up @@ -196,11 +207,8 @@ jobs:
d:\a\YUViewQt\YUViewQt\Qt\bin\qmake CONFIG+=UNITTESTS ..
echo "Executing jom:"
jom
- name: Run tests
run: |
cd build
nmake check
cd ..
- name: Run Unittests
run: D:\a\YUView\YUView\build\YUViewUnitTest\YUViewUnitTest
- name: WindeployQT
run: |
mkdir deploy
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "submodules/googletest"]
path = submodules/googletest
url = git@github.com:google/googletest.git
4 changes: 4 additions & 0 deletions YUView.pro
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ YUViewLib.subdir = YUViewLib
YUViewApp.depends = YUViewLib

UNITTESTS {
SUBDIRS += Googletest
Googletest.subdir = submodules/googletest-qmake

SUBDIRS += YUViewUnitTest
YUViewUnitTest.subdir = YUViewUnitTest
YUViewUnitTest.depends = Googletest
YUViewUnitTest.depends = YUViewLib
}
219 changes: 125 additions & 94 deletions YUViewLib/src/common/EnumMapper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* This file is part of YUView - The YUV player with advanced analytics toolset
* <https://github.com/IENT/YUView>
* Copyright (C) 2015 Institut f�r Nachrichtentechnik, RWTH Aachen University, GERMANY
* Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -32,135 +32,166 @@

#pragma once

#include <common/Functions.h>

#include <map>
#include <algorithm>
#include <array>
#include <iterator>
#include <optional>
#include <stdexcept>
#include <string>
#include <vector>
#include <string_view>

/* This class implement mapping of "enum class" values to and from names (string).
*/
template <typename T> class EnumMapper
{
public:
enum class StringType
{
Name,
Text,
NameOrIndex
};
struct Entry
{
Entry(T value, std::string name) : value(value), name(name) {}
Entry(T value, std::string name, std::string text) : value(value), name(name), text(text) {}
T value;
std::string name;
std::string text;
};
#include "Functions.h"

using EntryVector = std::vector<Entry>;
using namespace std::string_view_literals;

EnumMapper() = default;
EnumMapper(const EntryVector &entryVector) : entryVector(entryVector){};
template <class ValueType, std::size_t N> struct EnumMapper
{
public:
using ValueNamePair = std::pair<ValueType, std::string_view>;
using ItemArray = std::array<ValueType, N>;
using ItemIterator = typename ItemArray::const_iterator;
using NameArray = std::array<std::string_view, N>;
using NameIterator = typename NameArray::const_iterator;

std::optional<T> getValue(std::string name, StringType stringType = StringType::Name) const
struct Iterator
{
if (stringType == StringType::NameOrIndex)
if (auto index = functions::toUnsigned(name))
return this->at(*index);
using iterator_category = std::forward_iterator_tag;
using difference_type = int;
using value_type = ValueNamePair;
using pointer = ValueNamePair *;
using reference = ValueNamePair &;

for (const auto &entry : this->entryVector)
Iterator(const ItemIterator itItem, const NameIterator itName) : itItem(itItem), itName(itName)
{
if ((stringType == StringType::Name && entry.name == name) ||
(stringType == StringType::NameOrIndex && entry.text == name) ||
(stringType == StringType::Text && entry.text == name))
return entry.value;
this->valueNamePair.first = *itItem;
this->valueNamePair.second = *itName;
}
return {};
}

std::optional<T> getValueCaseInsensitive(std::string name,
StringType stringType = StringType::Name) const
{
if (stringType == StringType::NameOrIndex)
if (auto index = functions::toUnsigned(name))
return this->at(*index);
ValueNamePair const &operator*() const { return this->valueNamePair; }
ValueNamePair const *operator->() const { return &this->valueNamePair; }

name = functions::toLower(name);
for (const auto &entry : this->entryVector)
Iterator &operator++()
{
if ((stringType == StringType::Name && functions::toLower(entry.name) == name) ||
(stringType == StringType::NameOrIndex && functions::toLower(entry.text) == name) ||
(stringType == StringType::Text && functions::toLower(entry.text) == name))
return entry.value;
++this->itItem;
++this->itName;
this->valueNamePair.first = *this->itItem;
this->valueNamePair.second = *this->itName;
return *this;
}
return {};
}

std::string getName(T value) const
friend bool operator==(const Iterator &a, const Iterator &b)
{
return a.itItem == b.itItem && a.itName == b.itName;
};
friend bool operator!=(const Iterator &a, const Iterator &b)
{
return a.itItem != b.itItem || a.itName != b.itName;
};

private:
ItemIterator itItem;
NameIterator itName;
ValueNamePair valueNamePair{};
};

Iterator begin() const { return Iterator(this->items.begin(), this->names.begin()); }
Iterator end() const { return Iterator(this->items.end(), this->names.end()); }

template <typename... Args> constexpr EnumMapper(Args... args)
{
for (const auto &entry : this->entryVector)
if (entry.value == value)
return entry.name;
throw std::logic_error(
"The given type T was not registered in the mapper. All possible enums must be mapped.");
static_assert(sizeof...(Args) == N);
this->addElementsRecursively(0, args...);
}

std::string getText(T value) const
constexpr std::size_t size() const { return N; }

constexpr std::string_view getName(const ValueType value) const
{
for (const auto &entry : this->entryVector)
if (entry.value == value)
return entry.text;
throw std::logic_error(
"The given type T was not registered in the mapper. All possible enums must be mapped.");
const auto it = std::find(this->items.begin(), this->items.end(), value);
if (it == this->items.end())
throw std::logic_error(
"The given type T was not registered in the mapper. All possible enums must be mapped.");
const auto index = std::distance(this->items.begin(), it);
return this->names.at(index);
}

size_t indexOf(T value) const
constexpr std::optional<ValueType> getValue(const std::string_view name) const
{
for (size_t i = 0; i < this->entryVector.size(); i++)
if (this->entryVector.at(i).value == value)
return i;
throw std::logic_error(
"The given type T was not registered in the mapper. All possible enums must be mapped.");
const auto it =
std::find_if(this->begin(),
this->end(),
[&name](const ValueNamePair &pair) { return pair.second == name; });
if (it == this->end())
return {};

return it->first;
}

std::optional<T> at(size_t index) const
constexpr std::optional<ValueType> getValueCaseInsensitive(const std::string_view name) const
{
if (index >= this->entryVector.size())
const auto compareToNameLowercase = [&name](const std::string_view str)
{
if (name.length() != str.length())
return false;
for (std::size_t i = 0; i < name.length(); ++i)
{
if (std::tolower(name.at(i)) != std::tolower(str.at(i)))
return false;
}
return true;
};

const auto it = std::find_if(this->names.begin(), this->names.end(), compareToNameLowercase);
if (it == this->names.end())
return {};
return this->entryVector.at(index).value;

const auto index = std::distance(this->names.begin(), it);
return this->items.at(index);
}

std::vector<T> getEnums() const
std::optional<ValueType> getValueFromNameOrIndex(const std::string_view nameOrIndex) const
{
std::vector<T> m;
for (const auto &entry : this->entryVector)
m.push_back(entry.value);
return m;
if (auto index = functions::toUnsigned(nameOrIndex))
if (*index < N)
return this->items.at(*index);

return this->getValue(nameOrIndex);
}

std::vector<std::string> getNames() const
constexpr size_t indexOf(const ValueType value) const
{
std::vector<std::string> l;
for (const auto &entry : this->entryVector)
l.push_back(entry.name);
return l;
const auto it = std::find(this->items.begin(), this->items.end(), value);
if (it == this->items.end())
throw std::logic_error(
"The given type T was not registered in the mapper. All possible enums must be mapped.");

const auto index = std::distance(this->items.begin(), it);
return index;
}

std::vector<std::string> getTextEntries() const
constexpr std::optional<ValueType> at(const size_t index) const
{
std::vector<std::string> l;
for (const auto &entry : this->entryVector)
l.push_back(entry.text);
return l;
if (index >= N)
return {};
return this->items.at(index);
}

size_t size() const { return this->entryVector.size(); }

const EntryVector &entries() const { return this->entryVector; }
constexpr const ItemArray &getValues() const { return this->items; }
constexpr const NameArray &getNames() const { return this->names; }

private:
EntryVector entryVector;
constexpr void addElementsRecursively(const std::size_t) {};

template <typename ArgumentType, typename... Args>
constexpr void addElementsRecursively(const std::size_t index, ArgumentType first, Args... args)
{
static_assert(std::is_same<ValueNamePair, ArgumentType>());

const auto [value, name] = first;
this->items[index] = value;
this->names[index] = name;

addElementsRecursively(index + 1, args...);
}

ItemArray items{};
NameArray names{};
};
Loading

0 comments on commit 8e13a10

Please sign in to comment.