summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qdoc/CMakeLists.txt6
-rw-r--r--tests/auto/qdoc/catch_generators/CMakeLists.txt1
-rw-r--r--tests/auto/qdoc/catch_generators/qdoc_catch_generators.h5
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/combinators/cycle_generator.h80
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/combinators/oneof_generator.h185
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/k_partition_of_r_generator.h113
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/path_generator.h853
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/qchar_generator.h110
-rw-r--r--tests/auto/qdoc/catch_generators/src/generators/qstring_generator.h92
-rw-r--r--tests/auto/qdoc/catch_generators/src/namespaces.h11
-rw-r--r--tests/auto/qdoc/catch_generators/src/utilities/semantics/copy_value.h26
-rw-r--r--tests/auto/qdoc/catch_generators/src/utilities/semantics/generator_handler.h97
-rw-r--r--tests/auto/qdoc/catch_generators/src/utilities/semantics/move_into_vector.h62
-rw-r--r--tests/auto/qdoc/catch_generators/src/utilities/statistics/distribution.h158
-rw-r--r--tests/auto/qdoc/catch_generators/src/utilities/statistics/percentages.h49
-rw-r--r--tests/auto/qdoc/catch_generators/tests/CMakeLists.txt21
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/catch_k_partition_of_r_generator.cpp41
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/catch_path_generator.cpp755
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/catch_qchar_generator.cpp102
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/catch_qstring_generator.cpp89
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_cycle_generator.cpp70
-rw-r--r--tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_oneof_generator.cpp362
-rw-r--r--tests/auto/qdoc/catch_generators/tests/main.cpp9
-rw-r--r--tests/auto/qdoc/catch_generators/tests/utilities/semantics/catch_generator_handler.cpp28
-rw-r--r--tests/auto/qdoc/qdoc/CMakeLists.txt2
-rw-r--r--tests/auto/qdoc/qdoc/boundaries/filesystem/catch_directorypath.cpp2
-rw-r--r--tests/auto/qdoc/qdoc/boundaries/filesystem/catch_filepath.cpp2
-rw-r--r--tests/auto/qdoc/qdoc/filesystem/catch_fileresolver.cpp2
28 files changed, 9 insertions, 3324 deletions
diff --git a/tests/auto/qdoc/CMakeLists.txt b/tests/auto/qdoc/CMakeLists.txt
index a2c3ae274..08e79d8bf 100644
--- a/tests/auto/qdoc/CMakeLists.txt
+++ b/tests/auto/qdoc/CMakeLists.txt
@@ -6,10 +6,14 @@ if(CMAKE_VERSION VERSION_LESS "3.19" AND MSVC AND QT_FEATURE_debug_and_release)
return()
endif()
+set(QDOC_PROJECT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../../../src/qdoc/)
set(QDOC_SOURCE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../../../src/qdoc/qdoc/)
set(QDOC_INCLUDE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../../../src/qdoc/qdoc/)
-add_subdirectory(catch_generators)
+if(QT_BUILD_STANDALONE_TESTS)
+ include(${QDOC_PROJECT_DIRECTORY}/catch_generators/tests/CMakeLists.txt)
+endif()
+
add_subdirectory(qdoc)
add_subdirectory(config)
add_subdirectory(generatedoutput)
diff --git a/tests/auto/qdoc/catch_generators/CMakeLists.txt b/tests/auto/qdoc/catch_generators/CMakeLists.txt
deleted file mode 100644
index 88c051636..000000000
--- a/tests/auto/qdoc/catch_generators/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(tests)
diff --git a/tests/auto/qdoc/catch_generators/qdoc_catch_generators.h b/tests/auto/qdoc/catch_generators/qdoc_catch_generators.h
deleted file mode 100644
index e99a57ec5..000000000
--- a/tests/auto/qdoc/catch_generators/qdoc_catch_generators.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#include "src/generators/qchar_generator.h"
-#include "src/generators/qstring_generator.h"
-#include "src/generators/path_generator.h"
diff --git a/tests/auto/qdoc/catch_generators/src/generators/combinators/cycle_generator.h b/tests/auto/qdoc/catch_generators/src/generators/combinators/cycle_generator.h
deleted file mode 100644
index b60600747..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/combinators/cycle_generator.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-#include "../../utilities/semantics/generator_handler.h"
-
-#include <catch/catch.hpp>
-
-#include <vector>
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- template<typename T>
- class CycleGenerator : public Catch::Generators::IGenerator<T> {
- public:
- CycleGenerator(Catch::Generators::GeneratorWrapper<T>&& generator)
- : generator{std::move(generator)},
- cache{},
- cache_index{0}
- {
- // REMARK: We generally handle extracting the first
- // value by using an handler, to avoid code
- // duplication and the possibility of an error.
- // In this specific case, we turn to a more "manual"
- // approach as it better models the cache-based
- // implementation, removing the need to not increment
- // cache_index the first time that next is called.
- cache.emplace_back(this->generator.get());
- }
-
- T const& get() const override { return cache[cache_index]; }
-
- bool next() override {
- if (generator.next()) {
- cache.emplace_back(generator.get());
- ++cache_index;
- } else {
- cache_index = (cache_index + 1) % cache.size();
- }
-
- return true;
- }
-
- private:
- Catch::Generators::GeneratorWrapper<T> generator;
-
- std::vector<T> cache;
- std::size_t cache_index;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
- /*!
- * Returns a generator that behaves like \a generator until \a
- * generator is exhausted, repeating the same generation that \a
- * generator produced, infinitely, afterwards.
- *
- * This is generally intended to produce infinite generators from
- * finite ones.
- *
- * For example, consider a generator that produces values based on
- * another generator that it owns.
- * If the owning generator needs to produce more values that the
- * owned generator can support, it might fail at some point.
- * By cycling over the owned generator, we can extend the sequence
- * of produced values so that enough are generated, in a controlled
- * way.
- *
- * The type T should generally be copyable for this generator to
- * work.
- */
- template<typename T>
- inline Catch::Generators::GeneratorWrapper<T> cycle(Catch::Generators::GeneratorWrapper<T>&& generator) {
- return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::CycleGenerator(std::move(generator))));
- }
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/generators/combinators/oneof_generator.h b/tests/auto/qdoc/catch_generators/src/generators/combinators/oneof_generator.h
deleted file mode 100644
index 5de9dcb6c..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/combinators/oneof_generator.h
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-#include "../../utilities/statistics/percentages.h"
-#include "../../utilities/semantics/generator_handler.h"
-
-#include <catch/catch.hpp>
-
-#include <vector>
-#include <random>
-#include <algorithm>
-#include <numeric>
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- template<typename T>
- class OneOfGenerator : public Catch::Generators::IGenerator<T> {
- public:
- OneOfGenerator(
- std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
- const std::vector<double>& weights
- ) : generators{std::move(generators)},
- random_engine{std::random_device{}()},
- choice_distribution{weights.cbegin(), weights.cend()}
- {
- assert(weights.size() == this->generators.size());
- assert(std::reduce(weights.cbegin(), weights.cend()) == Approx(100.0));
-
- std::transform(
- this->generators.begin(), this->generators.end(), this->generators.begin(),
- [](auto& generator){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(generator)); }
- );
-
- static_cast<void>(next());
- }
-
- T const& get() const override { return current_value; }
-
- bool next() override {
- std::size_t generator_index{choice_distribution(random_engine)};
-
- if (!generators[generator_index].next()) return false;
- current_value = generators[generator_index].get();
-
- return true;
- }
-
- private:
- std::vector<Catch::Generators::GeneratorWrapper<T>> generators;
-
- std::mt19937 random_engine;
- std::discrete_distribution<std::size_t> choice_distribution;
-
- T current_value;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
- /*!
- * Returns a generator whose set of elements is the union of the
- * set of elements of the generators in \a generators.
- *
- * Each time the generator produces a value, a generator from \a
- * generators is randomly chosen to produce the value.
- *
- * The distribution for the choice is given by \a weights.
- * The \e {ith} element in \a weights represent the percentage
- * probability of the \e {ith} element of \a generators to be
- * chosen.
- *
- * It follows that the size of \a weights must be the same as the
- * size of \a generators.
- *
- * Furthermore, the sum of elements in \a weights should be a
- * hundred.
- *
- * The generator produces values until a generator that is chosen
- * to produce a value is unable to do so.
- * The first such generator to do so will stop the generation
- * independently of the availability of the other generators.
- *
- * Similarly, values will be produced as long as the chosen
- * generator can produce a value, independently of the other
- * generators being exhausted already.
- */
- template<typename T>
- inline Catch::Generators::GeneratorWrapper<T> oneof(
- std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
- const std::vector<double>& weights
- ) {
- return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::OneOfGenerator(std::move(generators), weights)));
- }
-
-
- /*!
- * Returns a generator whose set of elements is the union of the
- * set of elements of the generators in \a generators and in which
- * the distribution of the generated elements is uniform over \a
- * generators.
- *
- * Each time the generator produces a value, a generator from \a
- * generators is randomly chosen to produce the value.
- *
- * Each generator from \a generators has the same chance of being
- * chosen.
- *
- * Do note that the distribution over the set of values is not
- * necessarily uniform.
- *
- * The generator produces values until a generator that is chosen
- * to produce a value is unable to do so.
- * The first such generator to do so will stop the generation
- * independently of the availability of the other generators.
- *
- * Similarly, values will be produced as long as the chosen
- * generator can produce a value, independently of the other
- * generators being exhausted already.
- */
- template<typename T>
- inline Catch::Generators::GeneratorWrapper<T> uniform_oneof(
- std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators
- ) {
- std::vector<double> weights(
- generators.size(),
- QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::uniform_probability(generators.size())
- );
- return oneof(std::move(generators), std::move(weights));
- }
-
- /*!
- * Returns a generator whose set of elements is the union of the
- * set of elements of the generators in \a generators and in which
- * the distribution of the generated elements is uniform over the
- * elements of \a generators.
- *
- * The generators in \a generator should have a uniform
- * distribution and be finite.
- * If the set of elements that the generators in \a generator is
- * not disjoint, the distribution will be skewed towards repeated
- * elements.
- *
- * Each time the generator produces a value, a generator from \a
- * generators is randomly chosen to produce the value.
- *
- * Each generator from \a generators has a probability of being
- * chosen based on the proportion of the cardinality of the subset
- * it produces.
- *
- * The \e {ith} element of \a amounts should contain the
- * cardinality of the set produced by the \e {ith} generator in \a
- * generators.
- *
- * The generator produces values until a generator that is chosen
- * to produce a value is unable to do so.
- * The first such generator to do so will stop the generation
- * independently of the availability of the other generators.
- *
- * Similarly, values will be produced as long as the chosen
- * generator can produce a value, independently of the other
- * generators being exhausted already.
- */
- template<typename T>
- inline Catch::Generators::GeneratorWrapper<T> uniformly_valued_oneof(
- std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
- const std::vector<std::size_t>& amounts
- ) {
- std::size_t total_amount{std::accumulate(amounts.cbegin(), amounts.cend(), std::size_t{0})};
-
- std::vector<double> weights;
- weights.reserve(amounts.size());
-
- std::transform(
- amounts.cbegin(), amounts.cend(),
- std::back_inserter(weights),
- [total_amount](auto element){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::percent_of(static_cast<double>(element), static_cast<double>(total_amount)); }
- );
-
- return oneof(std::move(generators), std::move(weights));
- }
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/generators/k_partition_of_r_generator.h b/tests/auto/qdoc/catch_generators/src/generators/k_partition_of_r_generator.h
deleted file mode 100644
index 832ee2838..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/k_partition_of_r_generator.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../namespaces.h"
-
-#include <catch/catch.hpp>
-
-#include <random>
-#include <numeric>
-#include <algorithm>
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- class KPartitionOfRGenerator : public Catch::Generators::IGenerator<std::vector<double>> {
- public:
- KPartitionOfRGenerator(double r, std::size_t k)
- : random_engine{std::random_device{}()},
- interval_distribution{0.0, r},
- k{k},
- r{r},
- current_partition(k)
- {
- assert(r >= 0.0);
- assert(k >= 1);
-
- static_cast<void>(next());
- }
-
- std::vector<double> const& get() const override { return current_partition; }
-
- bool next() override {
- if (k == 1) current_partition[0] = r;
- else {
- // REMARK: The following wasn't formally proved
- // but is based on intuition.
- // It is probably erroneous but is expected to be
- // good enough for our case.
-
- // REMARK: We aim to provide a non skewed
- // distribution for the elements of the partition.
- //
- // The reasoning for this is to ensure that our
- // testing surface has a good chance of hitting
- // many of the available elements between the many
- // runs.
- //
- // To approximate this, a specific algorithm was chosen.
- // The following code can be intuitively seen as doing the following:
- //
- // Consider an interval [0.0, r] on the real line, where r > 0.0.
- //
- // k - 1 > 0 elements of the interval are chosen,
- // partitioning the interval into disjoint
- // sub-intervals.
- //
- // ---------------------------------------------------------------------------------------------------------------------
- // | | | | |
- // 0 k_1 k_2 k_3 r
- // | | | | |
- // _______--------------------_______________________________________________________-----------------------------------
- // k_1 - 0 k_2 - k_1 k_3 - k_2 r - k_3
- // p1 p2 p3 p4
- //
- // The length of each sub interval is chosen as one of the elements of the partition.
- //
- // Trivially, the sum of the chosen elements is r.
- //
- // Furthermore, as long as the distribution used
- // to choose the elements of the original interval
- // is uniform, the probability of each partition
- // being produced should tend to being uniform
- // itself.
- std::generate(current_partition.begin(), current_partition.end() - 1, [this](){ return interval_distribution(random_engine); });
-
- current_partition.back() = r;
-
- std::sort(current_partition.begin(), current_partition.end());
- std::adjacent_difference(current_partition.begin(), current_partition.end(), current_partition.begin());
- }
-
- return true;
- }
-
- private:
- std::mt19937 random_engine;
- std::uniform_real_distribution<double> interval_distribution;
-
- std::size_t k;
- double r;
-
- std::vector<double> current_partition;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
- /*!
- * Returns a generator that generates collections of \a k elements
- * whose sum is \a r.
- *
- * \a r must be a real number greater or euqal to zero and \a k
- * must be a natural number greater than zero.
- *
- * The generated partitions tends to be uniformely distributed
- * over the set of partitions of r.
- */
- inline Catch::Generators::GeneratorWrapper<std::vector<double>> k_partition_of_r(double r, std::size_t k) {
- return Catch::Generators::GeneratorWrapper<std::vector<double>>(std::unique_ptr<Catch::Generators::IGenerator<std::vector<double>>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::KPartitionOfRGenerator(r, k)));
- }
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/generators/path_generator.h b/tests/auto/qdoc/catch_generators/src/generators/path_generator.h
deleted file mode 100644
index 875502e49..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/path_generator.h
+++ /dev/null
@@ -1,853 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-// TODO: Change the include paths to implicitly consider
-// `catch_generators` a root directory and change the CMakeLists.txt
-// file to make this possible.
-
-#include "../namespaces.h"
-#include "qchar_generator.h"
-#include "qstring_generator.h"
-#include "../utilities/semantics/move_into_vector.h"
-#include "../utilities/semantics/generator_handler.h"
-
-#if defined(Q_OS_WINDOWS)
-
- #include "combinators/cycle_generator.h"
-
-#endif
-
-#include <catch/catch.hpp>
-
-#include <random>
-
-#include <QChar>
-#include <QString>
-#include <QStringList>
-#include <QRegularExpression>
-
-#if defined(Q_OS_WINDOWS)
-
- #include <QStorageInfo>
-
-#endif
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
-
-
- struct PathGeneratorConfiguration {
- double multi_device_path_probability{0.5};
- double absolute_path_probability{0.5};
- double directory_path_probability{0.5};
- double has_trailing_separator_probability{0.5};
- std::size_t minimum_components_amount{1};
- std::size_t maximum_components_amount{10};
-
- PathGeneratorConfiguration& set_multi_device_path_probability(double amount) {
- multi_device_path_probability = amount;
- return *this;
- }
-
- PathGeneratorConfiguration& set_absolute_path_probability(double amount) {
- absolute_path_probability = amount;
- return *this;
- }
-
- PathGeneratorConfiguration& set_directory_path_probability(double amount) {
- directory_path_probability = amount;
- return *this;
- }
-
- PathGeneratorConfiguration& set_has_trailing_separator_probability(double amount) {
- has_trailing_separator_probability = amount;
- return *this;
- }
-
- PathGeneratorConfiguration& set_minimum_components_amount(std::size_t amount) {
- minimum_components_amount = amount;
- return *this;
- }
-
- PathGeneratorConfiguration& set_maximum_components_amount(std::size_t amount) {
- maximum_components_amount = amount;
- return *this;
- }
- };
-
- /*!
- * \class PathGeneratorConfiguration
- * \brief Defines some parameters to customize the generation of
- * paths by a PathGenerator.
- */
-
- /*!
- * \variable PathGeneratorConfiguration::multi_device_path_probability
- *
- * Every path produced by a PathGenerator configured with a
- * mutli_device_path_probability of n has a probability of n to be
- * \e {Multi-Device} and a probability of 1.0 - n to not be \a
- * {Multi-Device}.
- *
- * multi_device_path_probability should be a value in the range [0.0,
- * 1.0].
- */
-
- /*!
- * \variable PathGeneratorConfiguration::absolute_path_probability
- *
- * Every path produced by a PathGenerator configured with an
- * absolute_path_probability of n has a probability of n to be \e
- * {Absolute} and a probability of 1.0 - n to be \e {Relative}.
- *
- * absolute_path_probability should be a value in the range [0.0,
- * 1.0].
- */
-
- /*!
- * \variable PathGeneratorConfiguration::directory_path_probability
- *
- * Every path produced by a PathGenerator configured with a
- * directory_path_probability of n has a probability of n to be \e
- * {To a Directory} and a probability of 1.0 - n to be \e {To a
- * File}.
- *
- * directory_path_probability should be a value in the range [0.0,
- * 1.0].
- */
-
- /*!
- * \variable PathGeneratorConfiguration::has_trailing_separator_probability
- *
- * Every path produced by a PathGenerator configured with an
- * has_trailing_separator_probability of n has a probability of n
- * to \e {Have a Trailing Separator} and a probability of 1.0 - n
- * to not \e {Have a Trailing Separator}, when this is applicable.
- *
- * has_trailing_separator_probability should be a value in the
- * range [0.0, 1.0].
- */
-
- /*!
- * \variable PathGeneratorConfiguration::minimum_components_amount
- *
- * Every path produced by a PathGenerator configured with a
- * minimum_components_amount of n will be the concatenation of at
- * least n non \e {device}, non \e {root}, non \e {separator}
- * components.
- *
- * minimum_components_amount should be greater than zero and less
- * than maximum_components_amount.
- */
-
- /*!
- * \variable PathGeneratorConfiguration::maximum_components_amount
- *
- * Every path produced by a PathGenerator configured with a
- * maximum_components_amount of n will be the concatenation of at
- * most n non \e {device}, non \e {root}, non \e {separator} components.
- *
- * maximum_components_amount should be greater than or equal to
- * minimum_components_amount.
- */
-
-
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- class PathGenerator : public Catch::Generators::IGenerator<QString> {
- public:
- PathGenerator(
- Catch::Generators::GeneratorWrapper<QString>&& device_component_generator,
- Catch::Generators::GeneratorWrapper<QString>&& root_component_generator,
- Catch::Generators::GeneratorWrapper<QString>&& directory_component_generator,
- Catch::Generators::GeneratorWrapper<QString>&& filename_component_generator,
- Catch::Generators::GeneratorWrapper<QString>&& separator_component_generator,
- PathGeneratorConfiguration configuration = PathGeneratorConfiguration{}
- ) : device_component_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(device_component_generator))},
- root_component_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(root_component_generator))},
- directory_component_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(directory_component_generator))},
- filename_component_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(filename_component_generator))},
- separator_component_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(separator_component_generator))},
- random_engine{std::random_device{}()},
- components_amount_distribution{configuration.minimum_components_amount, configuration.maximum_components_amount},
- is_multi_device_distribution{configuration.multi_device_path_probability},
- is_absolute_path_distribution{configuration.absolute_path_probability},
- is_directory_path_distribution{configuration.directory_path_probability},
- has_trailing_separator{configuration.has_trailing_separator_probability},
- current_path{}
- {
- assert(configuration.minimum_components_amount > 0);
- assert(configuration.minimum_components_amount <= configuration.maximum_components_amount);
-
- if (!next())
- Catch::throw_exception("Not enough values to initialize the first string");
- }
-
- QString const& get() const override { return current_path; }
-
- bool next() override {
- std::size_t components_amount{components_amount_distribution(random_engine)};
-
- current_path = "";
-
- // REMARK: As per our specification of a path, we
- // do not count device components, and separators,
- // when considering the amount of components in a
- // path.
- // This is a tradeoff that is not necessarily
- // precise.
- // Counting those kinds of components, on one
- // hand, would allow a device component to stands
- // on its own as a path, for example "C:", which
- // might actually be correct in some path format.
- // On the other hand, counting those kinds of
- // components makes the construction of paths for
- // our model much more complex with regards, for
- // example, to the amount of component.
- //
- // Counting device components, since they can
- // appear both in relative and absolute paths,
- // makes the minimum amount of components
- // different for different kinds of paths.
- //
- // Since absolute paths always require a root
- // component, the minimum amount of components for
- // a multi-device absolute path is 2.
- //
- // But an absolute path that is not multi-device
- // would only require one minimum component.
- //
- // Similarly, problems arise with the existence of
- // Windows' relative multi-device path, which
- // require a leading separator component after a
- // device component.
- //
- // This problem mostly comes from our model
- // simplifying the definition of paths quite a bit
- // into binary-forms.
- // This simplifies the code and its structure,
- // sacrificing some precision.
- // The lost precision is almost none for POSIX
- // based paths, but is graver for DOS paths, since
- // they have a more complex specification.
- //
- // Currently, we expect that the paths that QDoc
- // will encounter will mostly be in POSIX-like
- // forms, even on Windows, and aim to support
- // that, such that the simplification of code is
- // considered a better tradeoff compared to the
- // loss of precision.
- //
- // If this changes, the model should be changed to
- // pursue a Windows-first modeling, moving the
- // categorization of paths from the current binary
- // model to the absolute, drive-relative and
- // relative triptych that Windows uses.
- // This more complex model should be able to
- // completely describe posix paths too, making it
- // a superior choice as long as the complexity is
- // warranted.
- //
- // Do note that the model similarly can become
- // inconsistent when used to generate format of
- // paths such as the one used in some resource
- // systems.
- // Those are considered out-of-scope for our needs
- // and were not taken into account when developing
- // this generator.
- if (is_multi_device_distribution(random_engine)) {
- if (!device_component_generator.next()) return false;
- current_path += device_component_generator.get();
- }
-
- // REMARK: Similarly to not counting other form of
- // components, we do not count root components
- // towards the amounts of components that the path
- // has to simplify the code.
- // To support the "special" root path on, for
- // example, posix systems, we require a more
- // complex branching logic that changes based on
- // the path being absolute or not.
- //
- // We don't expect root to be a particularly
- // useful path for QDoc purposes and expect to not
- // have to consider it for our tests.
- // If consideration for it become required, it is
- // possible to test it directly in the affected
- // systemss as a special case.
- //
- // If most systems are affected by the handling of
- // a root path, then the model should be slightly
- // changed to accommodate its generation.
- if (is_absolute_path_distribution(random_engine)) {
- if (!root_component_generator.next()) return false;
-
- current_path += root_component_generator.get();
- }
-
- std::size_t prefix_components_amount{std::max(std::size_t{1}, components_amount) - 1};
- while (prefix_components_amount > 0) {
- if (!directory_component_generator.next()) return false;
- if (!separator_component_generator.next()) return false;
-
- current_path += directory_component_generator.get() + separator_component_generator.get();
- --prefix_components_amount;
- }
-
- if (is_directory_path_distribution(random_engine)) {
- if (!directory_component_generator.next()) return false;
- current_path += directory_component_generator.get();
-
- if (has_trailing_separator(random_engine)) {
- if (!separator_component_generator.next()) return false;
- current_path += separator_component_generator.get();
- }
- } else {
- if (!filename_component_generator.next()) return false;
- current_path += filename_component_generator.get();
- }
-
- return true;
- }
-
- private:
- Catch::Generators::GeneratorWrapper<QString> device_component_generator;
- Catch::Generators::GeneratorWrapper<QString> root_component_generator;
- Catch::Generators::GeneratorWrapper<QString> directory_component_generator;
- Catch::Generators::GeneratorWrapper<QString> filename_component_generator;
- Catch::Generators::GeneratorWrapper<QString> separator_component_generator;
-
- std::mt19937 random_engine;
- std::uniform_int_distribution<std::size_t> components_amount_distribution;
- std::bernoulli_distribution is_multi_device_distribution;
- std::bernoulli_distribution is_absolute_path_distribution;
- std::bernoulli_distribution is_directory_path_distribution;
- std::bernoulli_distribution has_trailing_separator;
-
- QString current_path;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
-/*!
- * Returns a generator that produces QStrings that represent a
- * path in a filesystem.
- *
- * A path is formed by the following components, loosely based
- * on the abstraction that is used by std::filesystem::path:
- *
- * \list
- * \li \b {device}:
- * Represents the device on the filesystem that
- * the path should be considered in terms of.
- * This is an optional components that is sometimes
- * present on multi-device systems, such as Windows, to
- * distinguish which device the path refers to.
- * When present, it always appears before any other
- * component.
- * \li \b {root}:
- * A special sequence that marks the path as absolute.
- * This is an optional component that is present, always,
- * in absolute paths.
- * \li \b {directory}:
- * A component that represents a directory on the
- * filesystem that the path "passes-trough".
- * Zero or more of this components can be present in the
- * path.
- * A path pointing to a directory on the filesystem that
- * is not \e {root} always ends with a component of this
- * type.
- * \li \b {filename}:
- * A component that represents a file on the
- * filesystem.
- * When this component is present, it is present only once
- * and always as the last component of the path.
- * A path that has such a component is a path that points
- * to a file on the filesystem.
- * For some path formats, there is no difference in the
- * format of a \e {filename} and a \e {directory}.
- * \li \b {separator}:
- * A component that is interleaved between other types of
- * components to separate them so that they are
- * recognizable.
- * A path that points to a directory on the filesystem may
- * sometimes have a \e {separator} at the end, after the
- * ending \e {directory} component.
- * \endlist
- *
- * Each component is representable as a string and a path is a
- * concatenation of the string representation of some
- * components, with the following rules:
- *
- * \list
- * \li There is at most one \e {device} component.
- * \li If a \e {device} component is present it always
- * precedes all other components.
- * \li There is at most one \e {root} component.
- * \li If a \e {root} component is present it:
- * \list
- * \li Succeeds the \e {device} component if it is present.
- * \li Precedes every other components if the \e {device}
- * component is not present.
- * \endlist
- * \li There are zero or more \e {directory} component.
- * \li There is at most one \e {filename} component.
- * \li If a \e {filename} component is present it always
- * succeeds all other components.
- * \li Between any two successive \e {directory} components
- * there is a \e {separator} component.
- * \li Between each successive \e {directory} and \e
- * {filename} component there is a \e {separator} component.
- * \li If the last component is a \e {directory} component it
- * can be optionally followed by a \e {separator} component.
- * \li At least one component that is not a \e {device}, a \e
- * {root} or \e {separator} component is present.
- * \endlist
- *
- * For example, if "C:" is a \e {device} component, "\\" is a
- * \e {root} component, "\\" is a \e {separator} component,
- * "directory" is a \e {directory} component and "filename" is
- * a \e {filename} component, the following are all paths:
- *
- * "C:\\directory", "C:\\directory\\directory", "C:filename",
- * "directory\\directory\\", "\\directory\\filename", "filename".
- *
- * While the following aren't:
- *
- * "C:", "C:\\", "directory\\C:", "foo", "C:filename\\",
- * "filename\\directory\\filename", "filename\\filename",
- * "directorydirectory"."
- *
- * The format of different components type can be the same.
- * For example, the \e {root} and \e {separator} component in
- * the above example.
- * For the purpose of generation, we do not care about the
- * format itself and consider a component of a certain type
- * depending only on how it is generated/where it is generated
- * from.
- *
- * For example, if every component is formatted as the string
- * "a", the string "aaa" could be a generated path.
- * By the string alone, it is not possible to simply discern
- * which components form it, but it would be possible to
- * generate it if the first "a" is a \a {device} component,
- * the second "a" is a \e {root} component and the third "a"
- * is a \e {directory} or \e {filename} component.
- *
- * A path, is further said to have some properties, pairs of
- * which are exclusive to each other.
- *
- * A path is said to be:
- *
- * \list
- * \li \b {Multi-Device}:
- * When it contains a \e {device} component.
- * \li \b {Absolute}:
- * When it contains a \e {root} component.
- * If the path is \e {Absolute} it is not \e {Relative}.
- * \li \b {Relative}:
- * When it does not contain a \e {root} component.
- * If the path is \e {Relative} it is not \e {Absolute}.
- * \li \b {To a Directory}:
- * When its last component is a \e {directory} component
- * or a \e {directory} component followed by a \e
- * {separator} component.
- * If the path is \e {To a Directory} it is not \e {To a
- * File}.
- * \li \b {To a File}:
- * When its last component is a \e {filename}.
- * If the path is \e {To a File} it is not \e {To a
- * Directory}.
- * \endlist
- *
- * All path are \e {Relative/Absolute}, \e {To a
- * Directory/To a File} and \e {Multi-Device} or not.
- *
- * Furthermore, a path that is \e {To a Directory} and whose
- * last component is a \e {separator} component is said to \e
- * {Have a Trailing Separator}.
- */
- inline Catch::Generators::GeneratorWrapper<QString> path(
- Catch::Generators::GeneratorWrapper<QString>&& device_generator,
- Catch::Generators::GeneratorWrapper<QString>&& root_component_generator,
- Catch::Generators::GeneratorWrapper<QString>&& directory_generator,
- Catch::Generators::GeneratorWrapper<QString>&& filename_generator,
- Catch::Generators::GeneratorWrapper<QString>&& separator_generator,
- PathGeneratorConfiguration configuration = PathGeneratorConfiguration{}
- ) {
- return Catch::Generators::GeneratorWrapper<QString>(
- std::unique_ptr<Catch::Generators::IGenerator<QString>>(
- new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::PathGenerator(std::move(device_generator), std::move(root_component_generator), std::move(directory_generator), std::move(filename_generator), std::move(separator_generator), configuration)
- )
- );
- }
-
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- // REMARK: We need a bounded length for the generation of path
- // components as strings.
- // We trivially do not want components to be the empty string,
- // such that we have a minimum length of 1, but the maximum
- // length is more malleable.
- // We don't want components that are too long to avoid
- // incurring in a big performance overhead, as we may generate
- // many of them.
- // At the same time, we want some freedom in having diffent
- // length components.
- // The value that was chosen is based on the general value for
- // POSIX's NAME_MAX, which seems to tend to be 14 on many systems.
- // We see this value as a small enough but not too much value
- // that further brings with itself a relation to paths,
- // increasing our portability even if it is out of scope, as
- // almost no modern respects NAME_MAX.
- // We don't use POSIX's NAME_MAX directly as it may not be available
- // on all systems.
- inline static constexpr std::size_t minimum_component_length{1};
- inline static constexpr std::size_t maximum_component_length{14};
-
- /*!
- * Returns a generator that generates strings that are
- * suitable to be used as a root component in POSIX paths.
- *
- * As per
- * \l {https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_02},
- * this is any sequence of slash characters that is not of
- * length 2.
- */
- inline Catch::Generators::GeneratorWrapper<QString> posix_root() {
- return uniformly_valued_oneof(
- QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::move_into_vector(
- string(character('/', '/'), 1, 1),
- string(character('/', '/'), 3, maximum_component_length)
- ),
- std::vector{1, maximum_component_length - 3}
- );
- }
-
- /*!
- * Returns a generator that generates strings that are
- * suitable to be used as directory components in POSIX paths
- * and that use an alphabet that should generally be supported
- * by other systems.
- *
- * Components of this kind use the \l
- * {https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282}{Portable Filename Character Set}.
- */
- inline Catch::Generators::GeneratorWrapper<QString> portable_posix_directory_name() {
- return string(
- QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE::portable_posix_filename(),
- minimum_component_length, maximum_component_length
- );
- }
-
- /*!
- * Returns a generator that generates strings that are
- * suitable to be used as filenames in POSIX paths and that
- * use an alphabet that should generally be supported by
- * other systems.
- *
- * Filenames of this kind use the \l
- * {https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282}{Portable Filename Character Set}.
- */
- inline Catch::Generators::GeneratorWrapper<QString> portable_posix_filename() {
- // REMARK: "." and ".." always represent directories so we
- // avoid generating them. Other than this, there is no
- // difference between a file name and a directory name.
- return filter([](auto& filename) { return filename != "." && filename != ".."; }, portable_posix_directory_name());
- }
-
- /*!
- * Returns a generator that generates strings that can be used
- * as POSIX compliant separators.
- *
- * As per \l
- * {https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_271},
- * a separator is a sequence of one or more slashes.
- */
- inline Catch::Generators::GeneratorWrapper<QString> posix_separator() {
- return string(character('/', '/'), minimum_component_length, maximum_component_length);
- }
-
- /*!
- * Returns a generator that generates strings that can be
- * suitably used as logical drive names in Windows' paths.
- *
- * As per \l
- * {https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats#traditional-dos-paths}
- * and \l
- * {https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives},
- * they are composed of a single letter.
- * Each generated string always follows the lettet with a
- * colon, as it is specifically intended for path usages,
- * where this is required.
- *
- * We use only uppercase letters for the drives names albeit,
- * depending on case sensitivity, lowercase letter could be
- * used.
- */
- inline Catch::Generators::GeneratorWrapper<QString> windows_logical_drives() {
- // REMARK: If a Windows path is generated on Windows
- // itself, we expect that it may be used to interact with
- // the filesystem, similar to how we expect a POSIX path
- // to be used on Linux.
- // For this reason, we only generate a specific drive, the one
- // that contains the current working directory, so that we
- // know it is an actually available drive and to contain the
- // possible modifications to the filesystem to an easily
- // foundable place.
-
-#if defined(Q_OS_WINDOWS)
-
- auto root_device{QStorageInfo{QDir()}.rootPath().first(1) + ":"};
-
- return cycle(Catch::Generators::value(std::move(root_device)));
-
-#else
-
- return Catch::Generators::map(
- [](QString letter){ return letter + ':';},
- string(QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE::ascii_uppercase(), 1, 1)
- );
-
-#endif
- }
-
- /*!
- * Returns a generator that generate strings that can be used
- * as separators in Windows based paths.
- *
- * As per \l
- * {https://docs.microsoft.com/en-us/dotnet/api/system.io.path.directoryseparatorchar?view=net-6.0}
- * and \l
- * {https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats#canonicalize-separators},
- * this is a sequence of one or more backward or forward slashes.
- */
- inline Catch::Generators::GeneratorWrapper<QString> windows_separator() {
- return uniform_oneof(
- QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::move_into_vector(
- string(character('\\', '\\'), minimum_component_length, maximum_component_length),
- string(character('/', '/'), minimum_component_length, maximum_component_length)
- )
- );
- }
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
- /*!
- * Returns a generator that generates strings representing
- * POSIX compatible paths.
- *
- * The generated paths follows the format specified in \l
- * {https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_271}.
- *
- * The optional length-requirements, such as PATH_MAX and
- * NAME_MAX, are relaxed away as they are generally not
- * respected by modern systems.
- *
- * It is possible to set the probability of obtaining a
- * relative or absolute path through \a
- * absolute_path_probability and the one of obtaining a path
- * potentially pointing ot a directory or on a file through \a
- * directory_path_probability.
- */
- inline Catch::Generators::GeneratorWrapper<QString> relaxed_portable_posix_path(double absolute_path_probability = 0.5, double directory_path_probability = 0.5) {
- return path(
- // POSIX path are never multi-device, so that we have
- // provide an empty device component generator and set
- // the probability for Multi-Device paths to zero.
- string(character(), 0, 0),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::posix_root(),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::portable_posix_directory_name(),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::portable_posix_filename(),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::posix_separator(),
- PathGeneratorConfiguration{}
- .set_multi_device_path_probability(0.0)
- .set_absolute_path_probability(absolute_path_probability)
- .set_directory_path_probability(directory_path_probability)
- );
- }
-
- /*!
- * Returns a generator that produces strings that represents
- * traditional DOS paths as defined in \l
- * {https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats#traditional-dos-paths}.
- *
- * The directory and filename components of a path generated
- * in this way are, currently, restricted to use a portable
- * character set as defined by POSIX.
- *
- * Do note that most paths themselves, will not be portable, on
- * the whole, albeit they may be valid paths on other systems, as
- * Windows uses a path system that is generally incompatible with
- * other systems.
- *
- * Some possibly valid special path, such as a "C:" or "\"
- * will never be generated.
- */
- inline Catch::Generators::GeneratorWrapper<QString> traditional_dos_path(
- double absolute_path_probability = 0.5,
- double directory_path_probability = 0.5,
- double multi_device_path_probability = 0.5
- ) {
- return path(
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::windows_logical_drives(),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::windows_separator(),
- // REMAKR: Windows treats trailing dots as if they were a
- // component of their own, that is, as the special
- // relative paths.
- // This seems to not be correctly handled by Qt's
- // filesystem methods, resulting in inconsistencies when
- // one such path is encountered.
- // To avoid the issue, considering that an equivalent path
- // can be formed by actually having the dots on their own
- // as a component, we filter out all those paths that have
- // trailing dots but are not only composed of dots.
- Catch::Generators::filter(
- [](auto& path){ return !(path.endsWith(".") && path.contains(QRegularExpression("[^.]"))) ; },
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::portable_posix_directory_name()
- ),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::portable_posix_filename(),
- QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::windows_separator(),
- PathGeneratorConfiguration{}
- .set_multi_device_path_probability(multi_device_path_probability)
- .set_absolute_path_probability(absolute_path_probability)
- .set_directory_path_probability(directory_path_probability)
- );
- }
-
- // TODO: Find a good way to test the following functions.
- // native_path can probably be tied to the tests for the
- // OS-specific functions, with TEMPLATE_TEST_CASE.
- // The other ones may follow a similar pattern but require a bit
- // more work so that they tie to a specific case instead of the
- // general one.
- // Nonetheless, this approach is both error prone and difficult to
- // parse, because of the required if preprocessor directives,
- // and should be avoided if possible.
-
- /*!
- * Returns a generator that generates QStrings that represents
- * paths native to the underlying OS.
- *
- * On Windows, paths that refer to a drive always refer to the
- * root drive.
- *
- * native* functions should always be chosen when using paths for
- * testing interfacing with the filesystem itself.
- *
- * System outside Linux, macOS or Windows are not supported.
- */
- inline Catch::Generators::GeneratorWrapper<QString> native_path(double absolute_path_probability = 0.5, double directory_path_probability = 0.5) {
-#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
-
- return relaxed_portable_posix_path(absolute_path_probability, directory_path_probability);
-
-#elif defined(Q_OS_WINDOWS)
-
- // REMARK: When generating native paths for testing we
- // generally want to avoid relative paths that are
- // drive-specific, as we want them to be tied to a specific
- // working directory that may not be the current directory on
- // the drive.
- // Hence, we avoid generating paths that may have a drive component.
- // For tests where those kind of paths are interesting, a
- // specific Windows-only test should be made, using
- // traditional_dos_path to generate drive-relative paths only.
- return traditional_dos_path(absolute_path_probability, directory_path_probability, 0.0);
-
-#endif
- }
-
- /*!
- * Returns a generator that generates QStrings that represents
- * paths native to the underlying OS and that are always \e
- * {Relative}.
- *
- * Avoids generating paths that refer to a directory that is not
- * included in the path itself.
- *
- * System outside Linux, macOS or Windows are not supported.
- */
- inline Catch::Generators::GeneratorWrapper<QString> native_relative_path(double directory_path_probability = 0.5) {
- // REMARK: When testing, we generally use some specific
- // directory as a root for relative paths.
- // We want the generated path to be relative to that
- // directory because we need a clean state for the test to
- // be reliable.
- // When generating paths, it is possible, correctly, to
- // have a path that refers to that directory or some
- // parent of it, removing us from the clean state that we
- // need.
- // To avoid that, we filter out paths that end up referring to a directory that is not under our "root" directory.
- //
- // We can think of each generated component moving us
- // further down or up, in case of "..", a directory
- // hierarchy, or keeping us at the same place in case of
- // ".".
- // Any path that ends up under our original "root"
- // directory will safely keep our clean state for testing.
- //
- // Each "." keeps us at the same level in the hierarchy.
- // Each ".." moves us up one level in the hierarchy.
- // Each component that is not "." or ".." moves us down
- // one level into the hierarchy.
- //
- // Then, to avoid referring to the "root" directory or one
- // of its parents, we need to balance out each "." and
- // ".." with the components that precedes or follow their
- // appearance.
- //
- // Since "." keeps us at the same level, it can appear how
- // many times it wants as long as the path referes to the
- // "root" directory or a directory or file under it and at
- // least one other component referes to a directory or
- // file that is under the "root" directory.
- //
- // Since ".." moves us one level up in the hierarchy, a
- // sequence of n ".." components is safe when at least n +
- // 1 non "." or ".." components appear before it.
- //
- // To avoid the above problem, we filter away paths that
- // do not respect those rules.
- return Catch::Generators::filter(
- [](auto& path){
- QStringList components{path.split(QRegularExpression{R"((\\|\/)+)"}, Qt::SkipEmptyParts)};
- int depth{0};
-
- for (auto& component : components) {
- if (component == "..")
- --depth;
- else if (component != ".")
- ++depth;
-
- if (depth < 0) return false;
- }
-
- return (depth > 0);
- },
- native_path(0.0, directory_path_probability)
- );
- }
-
- /*!
- * Returns a generator that generates QStrings that represents
- * paths native to the underlying OS and that are always \e
- * {Relative} and \e {To a File}.
- *
- * System outside Linux, macOS or Windows are not supported.
- */
- inline Catch::Generators::GeneratorWrapper<QString> native_relative_file_path() {
- return native_relative_path(0.0);
- }
-
- /*!
- * Returns a generator that generates QStrings that represents
- * paths native to the underlying OS and that are always \e
- * {Relative} and \e {To a Directory}.
- *
- * System outside Linux, macOS or Windows are not supported.
- */
- inline Catch::Generators::GeneratorWrapper<QString> native_relative_directory_path() {
- return native_relative_path(1.0);
- }
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/generators/qchar_generator.h b/tests/auto/qdoc/catch_generators/src/generators/qchar_generator.h
deleted file mode 100644
index 33efc5ea4..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/qchar_generator.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../namespaces.h"
-#include "../utilities/semantics/move_into_vector.h"
-#include "combinators/oneof_generator.h"
-
-#include <catch/catch.hpp>
-
-#include <random>
-
-#include <QChar>
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- class QCharGenerator : public Catch::Generators::IGenerator<QChar> {
- public:
- QCharGenerator(
- char16_t lower_bound = std::numeric_limits<char16_t>::min(),
- char16_t upper_bound = std::numeric_limits<char16_t>::max()
- ) : random_engine{std::random_device{}()},
- distribution{static_cast<unsigned int>(lower_bound), static_cast<unsigned int>(upper_bound)}
- {
- assert(lower_bound <= upper_bound);
- static_cast<void>(next());
- }
-
- QChar const& get() const override { return current_character; }
-
- bool next() override {
- current_character = QChar(static_cast<char16_t>(distribution(random_engine)));
-
- return true;
- }
-
- private:
- QChar current_character;
-
- std::mt19937 random_engine;
- std::uniform_int_distribution<unsigned int> distribution;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
-
- /*!
- * Returns a generator of that generates elements of QChar whose
- * ucs value is in the range [\a lower_bound, \a upper_bound].
- *
- * When \a lower_bound = \a upper_bound, the generator infinitely
- * generates the same character.
- */
- inline Catch::Generators::GeneratorWrapper<QChar> character(char16_t lower_bound = std::numeric_limits<char16_t>::min(), char16_t upper_bound = std::numeric_limits<char16_t>::max()) {
- return Catch::Generators::GeneratorWrapper<QChar>(std::unique_ptr<Catch::Generators::IGenerator<QChar>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QCharGenerator(lower_bound, upper_bound)));
- }
-
-
- namespace QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE {
-
- namespace QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE {
-
- enum class Alphabets : std::size_t {digit, ascii_lowercase, ascii_uppercase, ascii_alpha, ascii_alphanumeric, portable_posix_filename};
-
- template<Alphabets alphabet>
- struct sizeof_alphabet;
-
- template<Alphabets alphabet>
- inline constexpr std::size_t sizeof_alphabet_v = sizeof_alphabet<alphabet>::value;
-
- template <> struct sizeof_alphabet<Alphabets::digit> { static constexpr std::size_t value{'9' - '0'}; };
- template <> struct sizeof_alphabet<Alphabets::ascii_lowercase> { static constexpr std::size_t value{'z' - 'a'}; };
- template<> struct sizeof_alphabet<Alphabets::ascii_uppercase> { static constexpr std::size_t value{'Z' - 'A'}; };
- template<> struct sizeof_alphabet<Alphabets::ascii_alpha> { static constexpr std::size_t value{sizeof_alphabet_v<Alphabets::ascii_lowercase> + sizeof_alphabet_v<Alphabets::ascii_uppercase>}; };
- template<> struct sizeof_alphabet<Alphabets::ascii_alphanumeric>{ static constexpr std::size_t value{sizeof_alphabet_v<Alphabets::ascii_alpha> + sizeof_alphabet_v<Alphabets::digit>}; };
-
- } // end QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE
-
-
- inline Catch::Generators::GeneratorWrapper<QChar> digit() {
- return Catch::Generators::GeneratorWrapper<QChar>(std::unique_ptr<Catch::Generators::IGenerator<QChar>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QCharGenerator('0', '9')));
- }
-
- inline Catch::Generators::GeneratorWrapper<QChar> ascii_lowercase() {
- return Catch::Generators::GeneratorWrapper<QChar>(std::unique_ptr<Catch::Generators::IGenerator<QChar>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QCharGenerator('a', 'z')));
- }
-
- inline Catch::Generators::GeneratorWrapper<QChar> ascii_uppercase() {
- return Catch::Generators::GeneratorWrapper<QChar>(std::unique_ptr<Catch::Generators::IGenerator<QChar>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QCharGenerator('A', 'Z')));
- }
-
- inline Catch::Generators::GeneratorWrapper<QChar> ascii_alpha() {
- return uniform_oneof(QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::move_into_vector(ascii_lowercase(), ascii_uppercase()));
- }
-
- inline Catch::Generators::GeneratorWrapper<QChar> ascii_alphanumeric() {
- return uniformly_valued_oneof(QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::move_into_vector(ascii_alpha(), digit()), std::vector{traits::sizeof_alphabet_v<traits::Alphabets::ascii_alpha> , traits::sizeof_alphabet_v<traits::Alphabets::digit>});
- }
-
- inline Catch::Generators::GeneratorWrapper<QChar> portable_posix_filename() {
- return uniformly_valued_oneof(QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::move_into_vector(ascii_alphanumeric(), character('.', '.'), character('-', '-'), character('_', '_')),
- std::vector{traits::sizeof_alphabet_v<traits::Alphabets::ascii_alphanumeric>, std::size_t{1}, std::size_t{1}, std::size_t{1}});
- }
-
- } // end QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE
-
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/generators/qstring_generator.h b/tests/auto/qdoc/catch_generators/src/generators/qstring_generator.h
deleted file mode 100644
index fe854d22f..000000000
--- a/tests/auto/qdoc/catch_generators/src/generators/qstring_generator.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../namespaces.h"
-#include "qchar_generator.h"
-#include "../utilities/semantics/generator_handler.h"
-
-#include <catch/catch.hpp>
-
-#include <random>
-
-#include <QString>
-
-namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE {
- namespace QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE {
-
- class QStringGenerator : public Catch::Generators::IGenerator<QString> {
- public:
- QStringGenerator(Catch::Generators::GeneratorWrapper<QChar>&& character_generator, qsizetype minimum_length, qsizetype maximum_length)
- : character_generator{QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(character_generator))},
- random_engine{std::random_device{}()},
- length_distribution{minimum_length, maximum_length},
- current_string{}
- {
- assert(minimum_length >= 0);
- assert(maximum_length >= 0);
- assert(minimum_length <= maximum_length);
-
- if (!next())
- Catch::throw_exception("Not enough values to initialize the first string");
- }
-
- QString const& get() const override { return current_string; }
-
- bool next() override {
- qsizetype length{length_distribution(random_engine)};
-
- current_string = QString();
- for (qsizetype length_index{0}; length_index < length; ++length_index) {
- if (!character_generator.next()) return false;
-
- current_string += character_generator.get();
- }
-
- return true;
- }
-
- private:
- Catch::Generators::GeneratorWrapper<QChar> character_generator;
-
- std::mt19937 random_engine;
- std::uniform_int_distribution<qsizetype> length_distribution;
-
- QString current_string;
- };
-
- } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
-
- /*!
- * Returns a generator that generates elements of QString from
- * some amount of elements taken from \a character_generator.
- *
- * The generated strings will have a length in the range
- * [\a minimum_length, \a maximum_length].
- *
- * For compatibility with the Qt API, it is possible to provide
- * negative bounds for the length. This is, nonetheless,
- * considered an error such that the bounds should always be
- * greater or equal to zero.
- *
- * It is similarly considered an error to have minimum_length <=
- * maximum_length.
- *
- * The provided generator will generate elements until \a
- * character_generator is exhausted.
- */
- inline Catch::Generators::GeneratorWrapper<QString> string(Catch::Generators::GeneratorWrapper<QChar>&& character_generator, qsizetype minimum_length, qsizetype maximum_length) {
- return Catch::Generators::GeneratorWrapper<QString>(std::unique_ptr<Catch::Generators::IGenerator<QString>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QStringGenerator(std::move(character_generator), minimum_length, maximum_length)));
- }
-
- /*!
- * Returns an infinite generator whose elements are the empty
- * QString.
- */
- inline Catch::Generators::GeneratorWrapper<QString> empty_string() {
- return Catch::Generators::GeneratorWrapper<QString>(std::unique_ptr<Catch::Generators::IGenerator<QString>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::QStringGenerator(character(), 0, 0)));
- }
-
-
-} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/namespaces.h b/tests/auto/qdoc/catch_generators/src/namespaces.h
deleted file mode 100644
index 7b954feb0..000000000
--- a/tests/auto/qdoc/catch_generators/src/namespaces.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#define QDOC_CATCH_GENERATORS_ROOT_NAMESPACE qdoc::catch_generators
-
-#define QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE details
-
-#define QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE traits
-
-#define QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE alphabets
-
-#define QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE QDOC_CATCH_GENERATORS_ROOT_NAMESPACE::QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::utils
diff --git a/tests/auto/qdoc/catch_generators/src/utilities/semantics/copy_value.h b/tests/auto/qdoc/catch_generators/src/utilities/semantics/copy_value.h
deleted file mode 100644
index 57798be1a..000000000
--- a/tests/auto/qdoc/catch_generators/src/utilities/semantics/copy_value.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-
-#include <type_traits>
-
-namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE {
-
- /*!
- * Forces \value to be copied in an expression context.
- *
- * This is used in contexts where inferences of a type that
- * requires generality might identify a reference when ownership
- * is required.
- *
- * Note that the compiler might optmize the copy away. This is a
- * non-issue as we are only interested in breaking lifetime
- * dependencies.
- */
- template<typename T>
- std::remove_reference_t<T> copy_value(T value) { return value; }
-
-} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/utilities/semantics/generator_handler.h b/tests/auto/qdoc/catch_generators/src/utilities/semantics/generator_handler.h
deleted file mode 100644
index 328627512..000000000
--- a/tests/auto/qdoc/catch_generators/src/utilities/semantics/generator_handler.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-
-#include <catch/catch.hpp>
-
-#include <optional>
-#include <cassert>
-
-namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE {
-
- template<typename T>
- class GeneratorHandler : public Catch::Generators::IGenerator<T> {
- public:
-
- GeneratorHandler(Catch::Generators::GeneratorWrapper<T>&& generator)
- : generator{std::move(generator)},
- first_call{true}
- {}
-
- T const& get() const override {
- assert(!first_call);
- return generator.get();
- }
-
- bool next() override {
- if (first_call) {
- first_call = false;
- return true;
- }
-
- return generator.next();
- }
-
- private:
- Catch::Generators::GeneratorWrapper<T> generator;
- bool first_call;
- };
-
-
- /*!
- * Returns a generator wrapping \a generator that ensures that
- * changes its semantics so that the first call to get should be
- * preceded by a call to next.
- *
- * Catch generators require that is valid to call get and obtain a
- * valid value on a generator that was just created.
- * That is, generators should be non-empty and their first value
- * should be initialized on construction.
- *
- * Normally, this is not a problem, and the next implementation of
- * the generator can be simply called in the constructor.
- * But when a generator depends on other generators, doing so will
- * generally skip the first value that the generator
- * produces, as the wrapping generator will need to advance the
- * underlying generator, losing the value in the process.
- * This is in particular, a problem, on generators that are finite
- * or infinite and ordered.
- *
- * To solve the issue, the original value can be saved before
- * advancing the generator or some code can be duplicated or
- * abstracted so that what a new element can be generated without
- * advancing the underlying generator.
- *
- * While this is acceptable, it can be error prone on more complex
- * generators, generators that randomly access a collection of
- * generators and so on.
- *
- * To simplify this process, this generator changes the semantics
- * of the wrapped generator such that the first value of the
- * generator is produced after the first call to next and the
- * generator is considered in an invalid state before the first
- * advancement.
- *
- * In this way, by wrapping all generators that a generator
- * depends on, the implementation required for the first value is
- * the same as the one required for all following values, with
- * regards to the sequencing of next and get operations,
- * simplifying the implementation of dependent generators.
- *
- * Do note that, while the generator returned by this function
- * implments the generator interface that Catch2 requires, it
- * cannot be normally used as a generator as it fails to comply
- * with the first value semantics that a generator requires.
- * Indeed, it should only be used as an intermediate wrapper for
- * the implementation of generators that depends on other
- * generators.
- */
- template<typename T>
- inline Catch::Generators::GeneratorWrapper<T> handler(Catch::Generators::GeneratorWrapper<T>&& generator) {
- return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new GeneratorHandler(std::move(generator))));
- }
-
-} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/utilities/semantics/move_into_vector.h b/tests/auto/qdoc/catch_generators/src/utilities/semantics/move_into_vector.h
deleted file mode 100644
index 5e780085b..000000000
--- a/tests/auto/qdoc/catch_generators/src/utilities/semantics/move_into_vector.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-
-#include <vector>
-#include <tuple>
-
-namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE {
-
- namespace QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE {
-
- /*!
- * Returns the type of the first element of Args.
- *
- * Args is expected to have at least one
- */
- template<typename... Args>
- using first_from_pack_t = std::tuple_element_t<0, std::tuple<Args...>>;
-
- } // end QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE
-
-
- /*!
- * Builds an std::vector by moving \a movables into it.
- *
- * \a movables must be made of homogenous types.
- *
- * This function is intended to allow the construction of an
- * std::vector<T>, where T is a move only type, as an expression,
- * to lighten the idiom.
- *
- * For example, Catch's GeneratorWrapper<T> adapts a
- * std::unique_ptr, which is move only, making it impossible to
- * build a std::vector from them in place.
- *
- * Then, everywhere this is needed, a more complex approach of
- * generating the collection of objects, generating a vector of a
- * suitable size and iterating the objects to move-emplace them in
- * the vector is required.
- *
- * This not only complicates the code but is incompatible with a
- * GENERATE expression, making it extremely hard, noisy and error
- * prone to use them together.
- *
- * In those cases, then, a call to move_into_vector can be used as
- * an expression to circumvent the problem.
- */
- template<typename... MoveOnlyTypes>
- inline auto move_into_vector(MoveOnlyTypes... movables) {
- std::vector<QDOC_CATCH_GENERATORS_TRAITS_NAMESPACE::first_from_pack_t<MoveOnlyTypes...>>
- moved_into_vector;
- moved_into_vector.reserve(sizeof...(movables));
-
- (moved_into_vector.emplace_back(std::move(movables)), ...);
-
- return moved_into_vector;
- }
-
-} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/utilities/statistics/distribution.h b/tests/auto/qdoc/catch_generators/src/utilities/statistics/distribution.h
deleted file mode 100644
index 4374993bf..000000000
--- a/tests/auto/qdoc/catch_generators/src/utilities/statistics/distribution.h
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-
-#include <functional>
-#include <optional>
-#include <ostream>
-#include <unordered_map>
-
-namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE {
-
- template<typename T>
- using Histogram = std::unordered_map<T, std::size_t>;
-
- template<typename InputIt, typename GroupBy>
- auto make_histogram(InputIt begin, InputIt end, GroupBy&& group_by) {
- Histogram<std::invoke_result_t<GroupBy, decltype(*begin)>> histogram{};
-
- while (begin != end) {
- auto key{std::invoke(std::forward<GroupBy>(group_by), *begin)};
-
- histogram.try_emplace(key, 0);
- histogram[key] += 1;
- ++begin;
- }
-
- return histogram;
- }
-
- template<typename T>
- struct DistributionError {
- T value;
- double probability;
- double expected_probability;
- };
-
- template<typename T>
- inline std::ostream& operator<<(std::ostream& os, const DistributionError<T>& error) {
- return os << "DistributionError{" <<
- "The value { " << error.value <<
- " } appear with a probability of { " << error.probability <<
- " } while a probability of { " << error.expected_probability << " } was expected." <<
- "}";
- }
-
- // REMARK: The following should really return an Either of unit/error
- // but std::variant in C++ is both extremely unusable and comes with a
- // strong overhead unless certain conditions are met.
- // For this reason, we keep to the less intutitive optional error.
-
- /*!
- * Returns true when the given \a sequence approximately respects a
- * given distribution.
- *
- * The \a sequence respects a given distribution when the count of
- * each collection of values is a percentage of the total values that
- * is near the percentage probability described by distribution.
- *
- * The values in \a sequence are collected according to \a group_by.
- * \a group_by, given an element of \a sequence, should return a value
- * of some type that represent the category of the inspected value.
- * Values that have the same category share their count.
- *
- * The distribution that should be respected is given by \a
- * probability_of. \a probability_of is a function that takes a
- * category that was produced from a call to \a group_by and returns
- * the expect probability, in percentage, of apperance for that
- * category.
- *
- * The given probability is then compared to the one found by counting
- * the element of \a sequence under \a group_by, to ensure that it
- * matches.
- *
- * The margin of error for the comparison is given, in percentage
- * points, by \a margin.
- * The approximation uses an absolute comparison and scales the
- * margin inversely based on the size of \a sequence, to account for the
- * precision of the data set itself.
- *
- * When the distribution is not respected, a DistributionError is
- * returned enclosed in an optional value.
- * The error allows reports which the first category for which the
- * comparison failed, along with its expected probability and the one
- * that was actually inferred from \a sequence.
- */
- template<typename T, typename GroupBy, typename ProbabilityOf>
- std::optional<DistributionError<T>> respects_distribution(std::vector<T>&& sequence, GroupBy&& group_by, ProbabilityOf&& probability_of, double margin = 33) {
- std::size_t data_point_amount{sequence.size()};
-
- // REMARK: We scale the margin based on the data set to allow for
- // an easier change in downstream tests.
- // The precision required for the approximation will vary
- // depending on how many values we generate.
- // The amount of values we generate depends on how much time we
- // want the tests to take.
- // This amount may change in the future. For example, as code is
- // added and tests are added, we might need some expensive
- // computations here and there.
- // Sometimes, this will increase the test suite runtime without an
- // obvious way of improving the performance of the underlying code
- // to reduce it.
- // In those cases, the total run time can be decreased by running
- // less generations for battle-tested tests.
- // If some code has not been changed for a long time, it will have
- // had thousands of generations by that point, giving us a good
- // degree of certainty of it not being bugged (for whatever bugs
- // the tests account for).
- // Then, running a certain amount of generation is not required
- // anymore such that some of them can be optimized out.
- // For tests like the one using this function, where our ability
- // to test is always dependent on the amount of generations,
- // changing the generated amount will mean that we will need to
- // change our conditions too, potentially changing the meaning of
- // the test.
- // To take this into account, we perform a scaling on the
- // condition itself, so that if the amount of data points that are
- // generated changes, we do not generally have to change anything
- // in the condition.
- //
- // For this case, we scale logarithmically_10 for the simple
- // reason that we tend to generate values in power of tens,
- // starting with the 100 values default that Quickcheck used.
- //
- // The default value for the margin on which the scaling is based,
- // was chosen heuristically.
- // As we expect generation under 10^3 to be generally meaningless
- // for this kind of testing, the value was chosen so that it would
- // start to normalize around that amount.
- // Deviation of about 5-10% were identified trough various
- // generations for an amount of data points near 1000, while a
- // deviation of about 1-3% was identified with about 10000 values.
- // With the chosen default value, the scaling approaches those
- // percentage points with some margin of error.
- //
- // We expect up to a 10%, or a bit more, deviation to be suitable
- // for our purposes, as it would still allow for a varied
- // distribution in downstream consumers.
- double scaled_margin{margin * (1.0/std::log10(data_point_amount))};
-
- auto histogram{make_histogram(sequence.begin(), sequence.end(), std::forward<GroupBy>(group_by))};
-
- for (auto& bin : histogram) {
- auto [key, count] = bin;
-
- double actual_percentage{percent_of(static_cast<double>(count), static_cast<double>(data_point_amount))};
- double expected_percentage{std::invoke(std::forward<ProbabilityOf>(probability_of), key)};
-
- if (!(actual_percentage == Approx(expected_percentage).margin(scaled_margin)))
- return std::make_optional(DistributionError<T>{key, actual_percentage, expected_percentage});
- }
-
- return std::nullopt;
- }
-
-} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/src/utilities/statistics/percentages.h b/tests/auto/qdoc/catch_generators/src/utilities/statistics/percentages.h
deleted file mode 100644
index 2d80a459f..000000000
--- a/tests/auto/qdoc/catch_generators/src/utilities/statistics/percentages.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "../../namespaces.h"
-
-#include <cassert>
-
-namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE {
-
- /*!
- * Returns the percentage of \amount over \a total.
- *
- * \a amount needs to be greater or equal to zero and \a total
- * needs to be greater than zero.
- */
- inline double percent_of(double amount, double total) {
- assert(amount >= 0.0);
- assert(total > 0.0);
-
- return (amount / total) * 100.0;
- }
-
- /*!
- * Given the cardinality of a set, returns the percentage
- * probability that applied to every element of the set generates
- * a uniform distribution.
- */
- inline double uniform_probability(std::size_t cardinality) {
- assert(cardinality > 0);
-
- return (100.0 / static_cast<double>(cardinality));
- }
-
- /*!
- * Returns a percentage probability that is equal to \a
- * probability.
- *
- * \a probability must be in the range [0.0, 1.0]
- */
- inline double probability_to_percentage(double probability) {
- assert(probability >= 0.0);
- assert(probability <= 1.0);
-
- return probability * 100.0;
- }
-
-} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
diff --git a/tests/auto/qdoc/catch_generators/tests/CMakeLists.txt b/tests/auto/qdoc/catch_generators/tests/CMakeLists.txt
deleted file mode 100644
index 76c366331..000000000
--- a/tests/auto/qdoc/catch_generators/tests/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
-
-qt_internal_add_test(tst_QDoc_Catch_Generators
- SOURCES
- main.cpp
- generators/catch_qchar_generator.cpp
- generators/catch_qstring_generator.cpp
- generators/catch_k_partition_of_r_generator.cpp
- generators/catch_path_generator.cpp
-
- generators/combinators/catch_oneof_generator.cpp
- generators/combinators/catch_cycle_generator.cpp
-
- utilities/semantics/catch_generator_handler.cpp
- INCLUDE_DIRECTORIES
- ../src
- LIBRARIES
- Qt::QDocCatchPrivate
- Qt::QDocCatchConversionsPrivate
-)
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/catch_k_partition_of_r_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/catch_k_partition_of_r_generator.cpp
deleted file mode 100644
index 9055c5411..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/catch_k_partition_of_r_generator.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "namespaces.h"
-#include "generators/k_partition_of_r_generator.h"
-
-#include <catch/catch.hpp>
-
-#include <numeric>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-
-SCENARIO("Generating a k-partition of a real number", "[Partition][Reals]") {
- GIVEN("A real number r greater or equal to zero") {
- double r = GENERATE(take(10, random(0.0, 1000000.0)));
-
- AND_GIVEN("An amount of desired elements k greater than zero") {
- std::size_t k = GENERATE(take(10, random(1, 100)));
-
- WHEN("A k-partition of r is generated") {
- auto k_partition = GENERATE_COPY(take(10, k_partition_of_r(r, k)));
-
- THEN("The partition contains k elements") {
- REQUIRE(k_partition.size() == k);
-
- AND_THEN("The sum of those elements is r") {
- REQUIRE(std::accumulate(k_partition.begin(), k_partition.end(), 0.0) == Approx(r));
- }
- }
- }
- }
- }
-}
-
-TEST_CASE("All 1-partition of r are singleton collection with r as their element", "[Partition][Reals][SpecialCase]") {
- double r = GENERATE(take(10, random(0.0, 1000000.0)));
- auto k_partition = GENERATE_COPY(take(10, k_partition_of_r(r, 1)));
-
- REQUIRE(k_partition.size() == 1);
- REQUIRE(k_partition.front() == r);
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/catch_path_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/catch_path_generator.cpp
deleted file mode 100644
index 968008a56..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/catch_path_generator.cpp
+++ /dev/null
@@ -1,755 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "namespaces.h"
-#include "generators/qchar_generator.h"
-#include "generators/qstring_generator.h"
-#include "generators/path_generator.h"
-#include "generators/combinators/cycle_generator.h"
-#include "utilities/statistics/percentages.h"
-#include "utilities/statistics/distribution.h"
-#include "utilities/semantics/copy_value.h"
-
-#include <catch_conversions/qt_catch_conversions.h>
-
-#include <catch/catch.hpp>
-
-#include <QString>
-#include <QStringList>
-#include <QRegularExpression>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-using namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE;
-
-using namespace Qt::StringLiterals;
-
-TEST_CASE("A path generated with a multi_device_path_probability of 1.0 always contains a device component.", "[Path][Content][SpecialCase]") {
- QString device_component_value{"C:"};
- auto path_generator = path(
- Catch::Generators::value(copy_value(device_component_value)),
- empty_string(),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(1.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(generated_path.contains(device_component_value));
-}
-
-TEST_CASE("A path generated with a multi_device_path_probability of 0.0 never contains a device component.", "[Path][Content][SpecialCase]") {
- QString device_component_value{"C:"};
- auto path_generator = path(
- Catch::Generators::value(copy_value(device_component_value)),
- empty_string(),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(0.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(!generated_path.contains(device_component_value));
-}
-
-TEST_CASE("A path generated with an absolute_path_probability of 1.0 always contains a root component.", "[Path][Content][SpecialCase]") {
- QString root_component_value{"\\"};
- auto path_generator = path(
- empty_string(),
- Catch::Generators::value(copy_value(root_component_value)),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}.set_absolute_path_probability(1.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(generated_path.contains(root_component_value));
-}
-
-TEST_CASE("A path generated with an absolute_path_probability of 0.0 never contains a root component.", "[Path][Content][SpecialCase]") {
- QString root_component_value{"\\"};
- auto path_generator = path(
- empty_string(),
- Catch::Generators::value(copy_value(root_component_value)),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}.set_absolute_path_probability(0.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(!generated_path.contains(root_component_value));
-}
-
-TEST_CASE("A path generated with a directory_path_probability of 1.0 always ends with a root, directory or directory followed by separator component.", "[Path][Content][SpecialCase]") {
- QString root_component_value{"root"};
- QString directory_component_value{"dir"};
- QString separator_component_value{"sep"};
-
- auto path_generator = path(
- cycle(Catch::Generators::value(QString("device"))),
- cycle(Catch::Generators::value(copy_value(root_component_value))),
- cycle(Catch::Generators::value(copy_value(directory_component_value))),
- cycle(Catch::Generators::value(QString("filename"))),
- cycle(Catch::Generators::value(copy_value(separator_component_value))),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE((
- generated_path.endsWith(root_component_value) ||
- generated_path.endsWith(directory_component_value) ||
- generated_path.endsWith(directory_component_value + separator_component_value)
- ));
-}
-
-TEST_CASE("A path generated with a directory_path_probability of 0.0 always ends with a filename component.", "[Path][Content][SpecialCase]") {
- QString filename_component_value{"file"};
-
- auto path_generator = path(
- cycle(Catch::Generators::value(QString("device"))),
- cycle(Catch::Generators::value(QString("root"))),
- cycle(Catch::Generators::value(QString("dir"))),
- cycle(Catch::Generators::value(copy_value(filename_component_value))),
- cycle(Catch::Generators::value(QString("sep"))),
- PathGeneratorConfiguration{}.set_directory_path_probability(0.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(generated_path.endsWith(filename_component_value));
-}
-
-TEST_CASE("A directory path generated with a has_trailing_separator_probability of 1.0 always ends with a separator component.", "[Path][Content][SpecialCase]") {
- QString separator_component_value{"sep"};
-
- auto path_generator = path(
- cycle(Catch::Generators::value(QString("device"))),
- cycle(Catch::Generators::value(QString("root"))),
- cycle(Catch::Generators::value(QString("directory"))),
- cycle(Catch::Generators::value(QString("filename"))),
- cycle(Catch::Generators::value(copy_value(separator_component_value))),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0).set_has_trailing_separator_probability(1.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(generated_path.endsWith(separator_component_value));
-}
-
-TEST_CASE("A directory path generated with a has_trailing_separator_probability of 0.0 never ends with a separator component.", "[Path][Content][SpecialCase]") {
- QString separator_component_value{"sep"};
-
- auto path_generator = path(
- cycle(Catch::Generators::value(QString("device"))),
- cycle(Catch::Generators::value(QString("root"))),
- cycle(Catch::Generators::value(QString("directory"))),
- cycle(Catch::Generators::value(QString("filename"))),
- cycle(Catch::Generators::value(copy_value(separator_component_value))),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0).set_has_trailing_separator_probability(0.0)
- );
-
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- REQUIRE(!generated_path.endsWith(separator_component_value));
-}
-
-SCENARIO("Binding a path to a component range", "[Path][Bounds]") {
- GIVEN("A minimum amount of components") {
- auto minimum_components_amount = GENERATE(take(100, random(std::size_t{1}, std::size_t{100})));
-
- AND_GIVEN("A maximum amount of components that is greater or equal than the minimum amount of components") {
- auto maximum_components_amount = GENERATE_COPY(take(100, random(minimum_components_amount, std::size_t{100})));
-
- WHEN("A path is generated from those bounds") {
- QString countable_component_value{"a"};
-
- QString generated_path = GENERATE_COPY(
- take(1,
- path(
- empty_string(),
- empty_string(),
- cycle(Catch::Generators::value(copy_value(countable_component_value))),
- cycle(Catch::Generators::value(copy_value(countable_component_value))),
- empty_string(),
- PathGeneratorConfiguration{}.set_minimum_components_amount(minimum_components_amount).set_maximum_components_amount(maximum_components_amount)
- )
- )
- );
-
- THEN("The amount of non device, non root, non separator components in the generated path is in the range [minimum_components_amount, maximum_components_amount]") {
- std::size_t components_amount{static_cast<std::size_t>(generated_path.count(countable_component_value))};
-
- REQUIRE(components_amount >= minimum_components_amount);
- REQUIRE(components_amount <= maximum_components_amount);
- }
- }
- }
- }
-}
-
-TEST_CASE(
- "When the maximum amount of components and the minimum amount of components are equal, all generated paths have the same amount of non device, non root, non separator components",
- "[Path][Bounds][SpecialCase]")
-{
- auto components_amount = GENERATE(take(10, random(std::size_t{1}, std::size_t{100})));
-
- QString countable_component_value{"a"};
- QString generated_path = GENERATE_COPY(
- take(10,
- path(
- empty_string(),
- empty_string(),
- cycle(Catch::Generators::value(copy_value(countable_component_value))),
- cycle(Catch::Generators::value(copy_value(countable_component_value))),
- empty_string(),
- PathGeneratorConfiguration{}.set_minimum_components_amount(components_amount).set_maximum_components_amount(components_amount)
- )
- )
- );
-
- REQUIRE(static_cast<std::size_t>(generated_path.count(countable_component_value)) == components_amount);
-}
-
-SCENARIO("The format of a path", "[Path][Contents]") {
- GIVEN("A series of components generators") {
- // TODO: Could probably move this to the global scope to
- // lighen the tests.
- QString device_component_value{"device"};
- QString root_component_value{"root"};
- QString directory_component_value{"dir"};
- QString filename_component_value{"file"};
- QString separator_component_value{"sep"};
-
- auto device_component_generator = cycle(Catch::Generators::value(copy_value(device_component_value)));
- auto root_component_generator = cycle(Catch::Generators::value(copy_value(root_component_value)));
- auto directory_component_generator = cycle(Catch::Generators::value(copy_value(directory_component_value)));
- auto filename_component_generator = cycle(Catch::Generators::value(copy_value(filename_component_value)));
- auto separator_component_generator = cycle(Catch::Generators::value(copy_value(separator_component_value)));
-
- AND_GIVEN("A generator of paths using those components generator") {
- // TODO: We should actually randomize the configuration by
- // making a simple generator for it.
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("At most one device component is in the generated path") {
- REQUIRE(generated_path.count(device_component_value) <= 1);
- }
-
- THEN("At most one root component is in the generated path") {
- REQUIRE(generated_path.count(root_component_value) <= 1);
- }
-
- THEN("At most one filename component is in the generated path") {
- REQUIRE(generated_path.count(filename_component_value) <= 1);
- }
-
- THEN("At least one non device, non root, non separator component is in the generated path") {
- REQUIRE((generated_path.contains(directory_component_value) || generated_path.contains(filename_component_value)));
- }
-
- THEN("There is a separator component between any two successive directory components") {
- // REMARK: To test this condition, which is not
- // easy to test directly, as, if the generator is
- // working as it should, the concept of successive
- // directories stops existing.
- // To test it, then, we split the condition into
- // two parts, that are easier to test, that
- // achieve the same effect.
- // First, if all directories have a separator
- // component between them, it is impossible to
- // have a directory component that is directly
- // followed by another directory component.
- // Second, when this holds, any two directory
- // components must have one or more non-directory
- // components between them.
- // For those directories that have exactly one
- // component between them, it must be a separator.
- // This is equivalent to the original condition as
- // long as it is not allowed for anything else to
- // be between two directory components that have
- // exactly one component between them.
- // This is true at the time of writing of this
- // test, such that this will work correctly, but
- // if this changes the test is invalidated.
- // If a test for the original condition is found
- // that is not contrived (as it is possible to
- // test the original condition but it is a bit
- // more complex than we would like the test to
- // be), it should replace this current
- // implementation to improve the resiliency of the
- // test.
- REQUIRE_FALSE(generated_path.contains(directory_component_value + directory_component_value));
-
- auto successive_directories_re{
- QRegularExpression(u"%1(%2)%3"_s.arg(directory_component_value)
- .arg(QStringList{device_component_value, root_component_value, filename_component_value, separator_component_value}.join("|"))
- .arg(directory_component_value)
- )};
-
- auto successive_directories_match(successive_directories_re.match(generated_path));
- while (successive_directories_match.hasMatch()) {
- auto in_between_component{successive_directories_match.captured(1)};
-
- // TODO: Having this in a loop makes it so
- // the amount of assertions will vary slightly
- // per-run.
- // It would be better to avoid this, even if
- // it should not really be a problem
- // generally.
- // Try to find a better way to express this
- // condition that does not require a loop.
- // This could be as easy as just collection
- // the results and then using a std::all_of.
- REQUIRE(in_between_component == separator_component_value);
-
- successive_directories_match = successive_directories_re.match(generated_path, successive_directories_match.capturedEnd(1));
- }
- }
-
-
- THEN("There is a separator component between each successive directory and filename components") {
- REQUIRE_FALSE(generated_path.contains(directory_component_value + filename_component_value));
-
- auto successive_directory_filename_re{
- QRegularExpression(u"%1(%2)%3"_s.arg(directory_component_value)
- .arg(QStringList{device_component_value, root_component_value, filename_component_value, separator_component_value}.join("|"))
- .arg(filename_component_value)
- )};
-
- auto successive_directory_filename_match(successive_directory_filename_re.match(generated_path));
- while (successive_directory_filename_match.hasMatch()) {
- auto in_between_component{successive_directory_filename_match.captured(1)};
-
- REQUIRE(in_between_component == separator_component_value);
-
- successive_directory_filename_match = successive_directory_filename_re.match(generated_path, successive_directory_filename_match.capturedEnd(1));
- }
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates Multi-Device paths") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(1.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("Exactly one device component is in the generated path") {
- REQUIRE(generated_path.count(device_component_value) == 1);
-
- AND_THEN("The device component is the first component in the generated path") {
- REQUIRE(generated_path.startsWith(device_component_value));
- }
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates Absolute paths") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_absolute_path_probability(1.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("Exactly one root component is in the generated path") {
- REQUIRE(generated_path.count(root_component_value) == 1);
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates Absolute paths that are not Multi-Device") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(0.0).set_absolute_path_probability(1.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("The root component is the first component in the generated path") {
- REQUIRE(generated_path.startsWith(root_component_value));
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates Multi-Device, Absolute paths") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(1.0).set_absolute_path_probability(1.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("The root component succeeds the device component in the generated path") {
- REQUIRE(generated_path.contains(device_component_value + root_component_value));
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates paths that are To a Directory and do not Have a Trailing Separator") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0).set_has_trailing_separator_probability(0.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("The last component of in the path is a directory component") {
- REQUIRE(generated_path.endsWith(directory_component_value));
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that generates paths that are To a Directory and Have a Trailing Separator") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0).set_has_trailing_separator_probability(1.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("The last component in the path is a separator component that is preceded by a directory component") {
- REQUIRE(generated_path.endsWith(directory_component_value + separator_component_value));
- }
- }
- }
-
-
- AND_GIVEN("A generator of paths using those components generator that generates paths that are To a File") {
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_directory_path_probability(0.0)
- );
-
- WHEN("A path is generated from that generator") {
- auto generated_path = GENERATE_REF(take(10, std::move(path_generator)));
-
- THEN("Exactly one filename component is in the path") {
- REQUIRE(generated_path.contains(filename_component_value));
-
- AND_THEN("The filename component is the last component in the path") {
- REQUIRE(generated_path.endsWith(filename_component_value));
- }
- }
- }
- }
- }
-}
-
-// REMARK: [mayfail][distribution]
-SCENARIO("Observing the distribution of paths based on their configuration", "[Path][Statistics][!mayfail]") {
- GIVEN("A series of components generators") {
- QString device_component_value{"device"};
- QString root_component_value{"root"};
- QString directory_component_value{"dir"};
- QString filename_component_value{"file"};
- QString separator_component_value{"sep"};
-
- auto device_component_generator = cycle(Catch::Generators::value(copy_value(device_component_value)));
- auto root_component_generator = cycle(Catch::Generators::value(copy_value(root_component_value)));
- auto directory_component_generator = cycle(Catch::Generators::value(copy_value(directory_component_value)));
- auto filename_component_generator = cycle(Catch::Generators::value(copy_value(filename_component_value)));
- auto separator_component_generator = cycle(Catch::Generators::value(copy_value(separator_component_value)));
-
- AND_GIVEN("A generator of paths using those components generator that produces paths that are Multi-Device with a probability of n") {
- double multi_device_path_probability = GENERATE(take(10, random(0.0, 1.0)));
-
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_multi_device_path_probability(multi_device_path_probability)
- );
-
- WHEN("A certain amount of paths are generated from that generator") {
- auto paths = GENERATE_REF(take(1, chunk(10000, std::move(path_generator))));
-
- THEN("The amount of paths that are Multi-Device approximately respects the given probability and the amount of paths that are not approximately respects a probability of 1 - n") {
- auto maybe_distribution_error{respects_distribution(
- std::move(paths),
- [&device_component_value](const QString& path){ return (path.startsWith(device_component_value)) ? "Multi-Device" : "Non Multi-Device"; },
- [multi_device_path_probability](const QString& key){ return probability_to_percentage((key == "Multi-Device") ? multi_device_path_probability : 1 - multi_device_path_probability); }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that produces paths that are Absolute with a probability of n") {
- double absolute_path_probability = GENERATE(take(10, random(0.0, 1.0)));
-
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_absolute_path_probability(absolute_path_probability)
- );
-
- WHEN("A certain amount of paths are generated from that generator") {
- auto paths = GENERATE_REF(take(1, chunk(10000, std::move(path_generator))));
-
- THEN("The amount of paths that are Absolute approximately respects the given probability and the amount of paths that are Relative approximately respects a probability of 1 - n") {
- auto maybe_distribution_error{respects_distribution(
- std::move(paths),
- [&root_component_value](const QString& path){ return (path.contains(root_component_value)) ? "Absolute" : "Relative"; },
- [absolute_path_probability](const QString& key){ return probability_to_percentage((key == "Absolute") ? absolute_path_probability : 1 - absolute_path_probability); }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that produces paths that are To a Directory with a probability of n") {
- double directory_path_probability = GENERATE(take(10, random(0.0, 1.0)));
-
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_directory_path_probability(directory_path_probability)
- );
-
- WHEN("A certain amount of paths are generated from that generator") {
- auto paths = GENERATE_REF(take(1, chunk(10000, std::move(path_generator))));
-
- THEN("The amount of paths that are To a Directory approximately respects the given probability and the amount of paths that are To a File approximately respects a probability of 1 - n") {
- auto maybe_distribution_error{respects_distribution(
- std::move(paths),
- [&filename_component_value](const QString& path){ return (path.contains(filename_component_value)) ? "To a File" : "To a Directory"; },
- [directory_path_probability](const QString& key){ return probability_to_percentage((key == "To a Directory") ? directory_path_probability : 1 - directory_path_probability); }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
-
- AND_GIVEN("A generator of paths using those components generator that produces paths that are To a Directory with a probability of n to Have a Trailing Separator") {
- double has_trailing_separator_probability = GENERATE(take(10, random(0.0, 1.0)));
-
- auto path_generator = path(
- std::move(device_component_generator),
- std::move(root_component_generator),
- std::move(directory_component_generator),
- std::move(filename_component_generator),
- std::move(separator_component_generator),
- PathGeneratorConfiguration{}.set_directory_path_probability(1.0).set_has_trailing_separator_probability(has_trailing_separator_probability)
- );
-
- WHEN("A certain amount of paths are generated from that generator") {
- auto paths = GENERATE_REF(take(1, chunk(10000, std::move(path_generator))));
-
- THEN("The amount of paths that are Have a Trailing Separator approximately respects the given probability and the amount of paths that do not Have a Trailing Separator approximately respects a probability of 1 - n") {
- auto maybe_distribution_error{respects_distribution(
- std::move(paths),
- [&separator_component_value](const QString& path){ return (path.endsWith(separator_component_value)) ? "Have a Trailing Separator" : "Doesn't Have a Trailing Separator"; },
- [has_trailing_separator_probability](const QString& key){ return probability_to_percentage((key == "Have a Trailing Separator") ? has_trailing_separator_probability : 1 - has_trailing_separator_probability); }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
- }
-}
-
-TEST_CASE("The first component of the passed in device components generator is not lost", "[Path][GeneratorFirstElement][SpecialCase]") {
- QString device_component_generator_first_value{"device"};
-
- auto generated_path = GENERATE_COPY(take(1,
- path(
- values({device_component_generator_first_value, QString{""}}),
- empty_string(),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}
- .set_multi_device_path_probability(1.0)
- .set_minimum_components_amount(1)
- .set_maximum_components_amount(1)
- )
- ));
-
- REQUIRE(generated_path.contains(device_component_generator_first_value));
-}
-
-TEST_CASE("The first component of the passed in root components generator is not lost", "[Path][GeneratorFirstElement][SpecialCase]") {
- QString root_component_generator_first_value{"root"};
-
- auto generated_path = GENERATE_COPY(take(1,
- path(
- empty_string(),
- values({root_component_generator_first_value, QString{""}}),
- empty_string(),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}
- .set_absolute_path_probability(1.0)
- .set_minimum_components_amount(1)
- .set_maximum_components_amount(1)
- )
- ));
-
- REQUIRE(generated_path.contains(root_component_generator_first_value));
-}
-
-TEST_CASE("The first component of the passed in directory components generator is not lost", "[Path][GeneratorFirstElement][SpecialCase]") {
- QString directory_component_generator_first_value{"dir"};
-
- auto generated_path = GENERATE_COPY(take(1,
- path(
- empty_string(),
- empty_string(),
- values({directory_component_generator_first_value, QString{""}}),
- empty_string(),
- empty_string(),
- PathGeneratorConfiguration{}
- .set_directory_path_probability(1.0)
- .set_minimum_components_amount(1)
- .set_maximum_components_amount(1)
- )
- ));
-
- REQUIRE(generated_path.contains(directory_component_generator_first_value));
-}
-
-TEST_CASE("The first component of the passed in filename components generator is not lost", "[Path][GeneratorFirstElement][SpecialCase]") {
- QString filename_component_generator_first_value{"dir"};
-
- auto generated_path = GENERATE_COPY(take(1,
- path(
- empty_string(),
- empty_string(),
- empty_string(),
- values({filename_component_generator_first_value, QString{""}}),
- empty_string(),
- PathGeneratorConfiguration{}
- .set_directory_path_probability(0.0)
- .set_minimum_components_amount(1)
- .set_maximum_components_amount(1)
- )
- ));
-
- REQUIRE(generated_path.contains(filename_component_generator_first_value));
-}
-
-TEST_CASE("The first component of the passed in separator components generator is not lost", "[Path][GeneratorFirstElement][SpecialCase]") {
- QString separator_component_generator_first_value{"sep"};
-
- auto generated_path = GENERATE_COPY(take(1,
- path(
- empty_string(),
- empty_string(),
- empty_string(),
- empty_string(),
- values({separator_component_generator_first_value, QString{""}}),
- PathGeneratorConfiguration{}
- .set_directory_path_probability(0.0)
- .set_minimum_components_amount(2)
- .set_maximum_components_amount(2)
- )
- ));
-
- REQUIRE(generated_path.contains(separator_component_generator_first_value));
-}
-
-SCENARIO("Generating paths that are suitable to be used on POSIX systems", "[Path][POSIX][Content]") {
- GIVEN("A generator that generates Strings representing paths on a POSIX system that are portable") {
- auto path_generator = relaxed_portable_posix_path();
-
- WHEN("A path is generated from it") {
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- THEN("The path is composed only by one or more characters in the class [-_./a-zA-Z0-9]") {
- REQUIRE(QRegularExpression{R"(\A[-_.\/a-zA-Z0-9]+\z)"}.match(generated_path).hasMatch());
- }
- }
- }
-}
-
-SCENARIO("Generating paths that are suitable to be used on Windows", "[Path][Windows][Content]") {
- GIVEN("A generator that generates Strings representing paths on a Windows system") {
- auto path_generator = traditional_dos_path();
-
- WHEN("A path is generated from it") {
- auto generated_path = GENERATE_REF(take(100, std::move(path_generator)));
-
- CAPTURE(generated_path);
-
- THEN("The path starts with an uppercase letter followed by a colon, a backward or forward slash or a character in the class [-_.a-zA-Z0-9]") {
- QRegularExpression beginning_re{"([A-Z]:|\\|\\/|[-_.a-zA-Z0-9])"};
-
- auto beginning_match{beginning_re.match(generated_path)};
-
- REQUIRE(beginning_match.hasMatch());
-
- generated_path.remove(0, beginning_match.capturedEnd());
-
- AND_THEN("The rest of the path is composed by zero or more characters in the class [-_./\\a-zA-Z0-9]") {
- REQUIRE(QRegularExpression{R"(\A[-_.\/\\a-zA-Z0-9]*\z)"}.match(generated_path).hasMatch());
- }
- }
- }
- }
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/catch_qchar_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/catch_qchar_generator.cpp
deleted file mode 100644
index 47ef23364..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/catch_qchar_generator.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "namespaces.h"
-#include "generators/qchar_generator.h"
-
-#include <catch_conversions/qt_catch_conversions.h>
-
-#include <catch/catch.hpp>
-
-#include <QChar>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-using namespace QDOC_CATCH_GENERATORS_QCHAR_ALPHABETS_NAMESPACE;
-
-SCENARIO("Binding a generated QChar to a range", "[QChar][Bounds]") {
- GIVEN("A lower bound") {
- auto lower_bound = GENERATE(take(100, random(
- static_cast<unsigned int>(std::numeric_limits<char16_t>::min()),
- static_cast<unsigned int>(std::numeric_limits<char16_t>::max())
- )));
-
- AND_GIVEN("An upper bound that is greater or equal than the lower bound") {
- auto upper_bound = GENERATE_COPY(take(100, random(lower_bound, static_cast<unsigned int>(std::numeric_limits<char16_t>::max()))));
-
- WHEN("A QChar is generated from those bounds") {
- QChar generated_character = GENERATE_COPY(take(1, character(lower_bound, upper_bound)));
-
- THEN("The generated character has a unicode value in the range [lower_bound, upper_bound]") {
- REQUIRE(generated_character.unicode() >= lower_bound);
- REQUIRE(generated_character.unicode() <= upper_bound);
- }
- }
- }
- }
-}
-
-TEST_CASE(
- "When lower_bound and upper_bound are equal, let their value be n, the only generated character is the one with unicode value n",
- "[QChar][Bounds]"
-) {
- auto bound = GENERATE(take(100, random(
- static_cast<unsigned int>(std::numeric_limits<char16_t>::min()),
- static_cast<unsigned int>(std::numeric_limits<char16_t>::max())
- )));
- auto generated_character = GENERATE_COPY(take(100, character(bound, bound)));
-
- REQUIRE(generated_character.unicode() == bound);
-}
-
-TEST_CASE("When generating digits, each generated character is in the class [0-9]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, digit()));
-
- REQUIRE(generated_character >= '0');
- REQUIRE(generated_character <= '9');
-}
-
-TEST_CASE("When generating lowercase ascii characters, each generated character is in the class [a-z]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, ascii_lowercase()));
-
- REQUIRE(generated_character >= 'a');
- REQUIRE(generated_character <= 'z');
-}
-
-TEST_CASE("When generating uppercase ascii characters, each generated character is in the class [A-Z]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, ascii_uppercase()));
-
- REQUIRE(generated_character >= 'A');
- REQUIRE(generated_character <= 'Z');
-}
-
-TEST_CASE("When generating ascii alphabetic characters, each generated character is in the class [a-zA-Z]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, ascii_alpha()));
-
- REQUIRE((
- (generated_character >= 'a' && generated_character <= 'z') ||
- (generated_character >= 'A' && generated_character <= 'Z')
- ));
-}
-
-TEST_CASE("When generating ascii alphabetic characters, each generated character is in the class [a-zA-Z0-9]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, ascii_alpha()));
-
- REQUIRE((
- (generated_character >= 'a' && generated_character <= 'z') ||
- (generated_character >= 'A' && generated_character <= 'Z') ||
- (generated_character >= '0' && generated_character <= '9')
- ));
-}
-
-TEST_CASE("When generating portable posix filename, each generated character is in the class [-_.a-zA-Z0-9]", "[QChar][SpecialCase]") {
- auto generated_character = GENERATE(take(100, ascii_alpha()));
-
- REQUIRE((
- (generated_character == '-') ||
- (generated_character == '_') ||
- (generated_character == '.') ||
- (generated_character >= 'a' && generated_character <= 'z') ||
- (generated_character >= 'A' && generated_character <= 'Z') ||
- (generated_character >= '0' && generated_character <= '9')
- ));
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/catch_qstring_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/catch_qstring_generator.cpp
deleted file mode 100644
index 75d7efcf1..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/catch_qstring_generator.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "namespaces.h"
-#include "generators/qchar_generator.h"
-#include "generators/qstring_generator.h"
-
-#include <catch_conversions/qt_catch_conversions.h>
-
-#include <catch/catch.hpp>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-
-#include <algorithm>
-
-SCENARIO("Binding a QString to a length range", "[QString][Bounds]") {
- GIVEN("A minimum length") {
- auto minimum_length = GENERATE(take(100, random(0, 100)));
-
- AND_GIVEN("A maximum length that is greater or equal than the minimum length") {
- auto maximum_length = GENERATE_COPY(take(100, random(minimum_length, 100)));
-
- WHEN("A QString is generated from those bounds") {
- QString generated_string = GENERATE_COPY(take(1, string(character(), minimum_length, maximum_length)));
-
- THEN("The generated string's length is in the range [minimum_length, maximum_length]") {
- REQUIRE(generated_string.size() >= minimum_length);
- REQUIRE(generated_string.size() <= maximum_length);
- }
- }
- }
- }
-}
-
-TEST_CASE("When the maximum length and the minimum length are zero all generated strings are the empty string", "[QString][Bounds][SpecialCase][BoundingValue]") {
- QString generated_string = GENERATE(take(100, string(character(), 0, 0)));
-
- REQUIRE(generated_string.isEmpty());
-}
-
-TEST_CASE("When the maximum length and the minimum length are equal, all generated strings have the same length equal to the given length", "[QString][Bounds][SpecialCase]") {
- auto length = GENERATE(take(100, random(0, 100)));
- auto generated_string = GENERATE_COPY(take(100, string(character(), length, length)));
-
- REQUIRE(generated_string.size() == length);
-}
-
-SCENARIO("Limiting the characters that can compose a QString", "[QString][Contents]") {
- GIVEN("A list of characters candidates") {
- auto lower_character_bound = GENERATE(take(10, random(
- static_cast<unsigned int>(std::numeric_limits<char16_t>::min()),
- static_cast<unsigned int>(std::numeric_limits<char16_t>::max())
- )));
- auto upper_character_bound = GENERATE_COPY(take(10, random(lower_character_bound, static_cast<unsigned int>(std::numeric_limits<char16_t>::max()))));
-
- auto character_candidates = character(lower_character_bound, upper_character_bound);
-
- WHEN("A QString is generated from that list") {
- QString generated_string = GENERATE_REF(take(100, string(std::move(character_candidates), 1, 50)));
-
- THEN("The string is composed only of characters that are in the list of characters") {
- REQUIRE(
- std::all_of(
- generated_string.cbegin(), generated_string.cend(),
- [lower_character_bound, upper_character_bound](QChar element){ return element.unicode() >= lower_character_bound && element.unicode() <= upper_character_bound; }
- )
- );
- }
- }
- }
-}
-
-TEST_CASE("The strings generated by a generator of empty string are all empty", "[QString][Contents]") {
- QString generated_string = GENERATE(take(100, empty_string()));
-
- REQUIRE(generated_string.isEmpty());
-}
-
-
-TEST_CASE("The first element of the passsed in generator is not lost", "[QString][GeneratorFirstElement][SpecialCase]") {
- QChar first_value{'a'};
-
- // REMARK: We use two values to avoid having the generator throw
- // an exception if the first element is actually lost.
- auto character_generator{Catch::Generators::values({first_value, QChar{'b'}})};
- auto generated_string = GENERATE_REF(take(1, string(std::move(character_generator), 1, 1)));
-
- REQUIRE(generated_string == QString{first_value});
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_cycle_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_cycle_generator.cpp
deleted file mode 100644
index 43bae006b..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_cycle_generator.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "namespaces.h"
-#include "generators/combinators/cycle_generator.h"
-
-#include <catch/catch.hpp>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-
-// REMARK: We use fixed-values-generators for those tests so that it
-// is trivial to identify when their generation will end, which
-// values we should expect and how many values we should expect.
-// This is unfortunately not general, but we don't have, by default,
-// enough tools to generalize this without having to provide our own
-// (being able to generate fixed values from a vector) and adding more
-// to the complexity, which is already high.
-
-TEST_CASE(
- "The xn + m element, where 0 < m < n, from a repeating generator whose underlying generator produces n elements, will produce an element equivalent to the mth element of the generation produced by the underlying generator",
- "[Cycle][Combinators]"
-) {
- std::size_t n{10};
-
- auto owned_generator{Catch::Generators::values({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'})};
- auto owned_generator_copy{Catch::Generators::values({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'})};
-
- auto original_generation = GENERATE_REF(take(1, chunk(n, std::move(owned_generator_copy))));
-
- std::size_t x = GENERATE(take(10, random(std::size_t{0}, std::size_t{20})));
- std::size_t m = GENERATE_COPY(take(10, random(std::size_t{1}, std::size_t{n})));
-
- auto repeating_generator = cycle(std::move(owned_generator));
- auto repeating_generation = GENERATE_REF(take(1, chunk((x * n) + m, std::move(repeating_generator))));
-
- REQUIRE(repeating_generation.back() == original_generation[m - 1]);
-}
-
-SCENARIO("Repeating a generation ad infinitum", "[Cycle][Combinators]") {
- GIVEN("Some finite generator") {
- std::size_t values_amount{3};
-
- auto owned_generator{Catch::Generators::values({'a', 'b', 'c'})};
- auto owned_generator_copy{Catch::Generators::values({'a', 'b', 'c'})};
-
- AND_GIVEN("A way to repeat the generation of that generator infinitely") {
- auto repeating_generator = cycle(std::move(owned_generator));
-
- WHEN("Generating exactly enough values to exhaust the original generator") {
- auto repeating_generation = GENERATE_REF(take(1, chunk(values_amount, std::move(repeating_generator))));
- auto original_generation = GENERATE_REF(take(1, chunk(values_amount, std::move(owned_generator_copy))));
-
- THEN("The repeating generator behaves equally to the original finite generator") {
- REQUIRE(repeating_generation == original_generation);
- }
- }
-
- WHEN("Generating exactly n times the amount of values required to exhaust the original generator") {
- std::size_t n = GENERATE(take(10, random(2, 10)));
-
- auto original_generation = GENERATE_REF(take(1, chunk(values_amount, std::move(owned_generator_copy))));
- auto repeating_generation = GENERATE_REF(take(n, chunk(values_amount, std::move(repeating_generator))));
-
- THEN("The n generation of the repeating generator are always the same as the generation of the original generation") {
- REQUIRE(repeating_generation == original_generation);
- }
- }
- }
- }
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_oneof_generator.cpp b/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_oneof_generator.cpp
deleted file mode 100644
index 68e990813..000000000
--- a/tests/auto/qdoc/catch_generators/tests/generators/combinators/catch_oneof_generator.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include <catch_conversions/std_catch_conversions.h>
-
-#include "namespaces.h"
-#include "generators/k_partition_of_r_generator.h"
-#include "generators/combinators/oneof_generator.h"
-#include "generators/combinators/cycle_generator.h"
-#include "utilities/statistics/percentages.h"
-#include "utilities/statistics/distribution.h"
-#include "utilities/semantics/copy_value.h"
-
-#include <catch/catch.hpp>
-
-#include <cmath>
-#include <iterator>
-#include <vector>
-#include <algorithm>
-#include <unordered_map>
-
-using namespace QDOC_CATCH_GENERATORS_ROOT_NAMESPACE;
-using namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE;
-
-SCENARIO("Choosing between one of many generators", "[OneOf][Combinators]") {
- GIVEN("Some generators producing values of the same type") {
- auto generators_amount = GENERATE(take(10, random(1, 10)));
- auto generators_values = GENERATE_COPY(take(10, chunk(generators_amount, random(0, 100000))));
-
- std::vector<Catch::Generators::GeneratorWrapper<int>> generators;
- generators.reserve(generators_amount);
- std::transform(
- generators_values.begin(), generators_values.end(), std::back_inserter(generators),
- [](auto& value){ return Catch::Generators::value(copy_value(value)); }
- );
-
- AND_GIVEN("A generator choosing between them based on some distribution") {
- std::vector<double> weights = GENERATE_COPY(take(10, k_partition_of_r(100.0, generators_amount)));
- auto choosing_generator = oneof(std::move(generators), std::move(weights));
-
- WHEN("A value is extracted from the choosing generator") {
- auto generated_value = GENERATE_REF(take(100, std::move(choosing_generator)));
-
- THEN("The generated value is a member of one of the original generators") {
- REQUIRE(std::find(generators_values.cbegin(), generators_values.cend(), generated_value) != generators_values.cend());
- }
- }
- }
-
- AND_GIVEN("A generator choosing between them with the same probability") {
- auto choosing_generator = uniform_oneof(std::move(generators));
-
- WHEN("A value is extracted from the choosing generator") {
- auto generated_value = GENERATE_REF(take(100, std::move(choosing_generator)));
-
- THEN("The generated value is a member of one of the original generators") {
- REQUIRE(std::find(generators_values.cbegin(), generators_values.cend(), generated_value) != generators_values.cend());
- }
- }
- }
-
- AND_GIVEN("A generator choosing between them such that each possible value has the same probability of being chosen") {
- auto choosing_generator = uniformly_valued_oneof(std::move(generators), std::vector(generators_amount, std::size_t{1}));
-
- WHEN("A value is extracted from the choosing generator") {
- auto generated_value = GENERATE_REF(take(100, std::move(choosing_generator)));
-
- THEN("The generated value is a member of one of the original generators") {
- REQUIRE(std::find(generators_values.cbegin(), generators_values.cend(), generated_value) != generators_values.cend());
- }
- }
- }
- }
-}
-
-// TODO: The following is a generally complex test. Nonetheless, we
-// can probably ease some of the complexity by moving it out into some
-// generators or by abstracting it a little to remove the need to know
-// some of the implementation details.
-// Check if this is possible.
-
-// REMARK: [mayfail][distribution]
-// This tests cannot be precise as it depends on randomized output.
-// For this reason, we mark it as !mayfail.
-// This allows us to see cases where it fails without having the
-// test-run itself fail.
-// We generally expect this test to not fail, but it may fail randomly
-// every now and then simply because of how a correctly randomized
-// distribution may behave.
-// As long as this test doesn't fail consistently, with values that
-// shows an unsustainable deviation, it should be considered to be
-// working.
-SCENARIO("Observing the distribution of generators that are chosen from", "[OneOf][Combinators][Statistics][!mayfail]") {
- GIVEN("Some generators producing values of the same type") {
- std::size_t generators_amount = GENERATE(take(10, random(1, 10)));
-
- // REMARK: To test the distribution, we want to have some
- // amount of generators to choose from whose generated values
- // can be uniquely reconducted to the generating generator so
- // that we may count how many times a specific generator was
- // chosen.
- // The easiest way would be to have generators that produce a
- // single value.
- // Nonetheless, to test the version that provides an
- // approximate uniform distribution over the values themselves
- // correctly, we need to have generators that can produce a
- // different amount of elements.
- // When that is not the case, indeed, a generator that
- // approximately distributes uniformly over values is
- // equivalent to one that approximately distributes uniformely
- // over the generators themselves.
- // As such, we use ranges of positive integers, as they are
- // the simplest multi-valued finite generator that can be dinamically
- // construted, while still providing an easy way to infer the
- // amount of values it contains so that we can derive the
- // cardinality of our domain.
- // We produce those ranges as disjoint subsequent ranges
- // starting from 0 upward.
- // We require the ranges to be disjoint so that we do not lose
- // the ability of uniquely identifying a generator that
- // produced the value.
- //
- // To do so, we generate a series of disjoint least upper
- // bounds for the ranges.
- // Then, we produce the ith range by using the successor of
- // the (i - 1)th upper bound as its lower bound and the ith
- // upper bound as its upper bound.
- //
- // We take further care to ensure that the collection of upper
- // bounds is sorted, as this simplifies to a linear search our
- // need to index the collection of generators to find the
- // identifying generator and its associated probability.
- std::vector<std::size_t> generators_bounds(generators_amount, 0);
- std::vector<Catch::Generators::GeneratorWrapper<std::size_t>> generators;
- generators.reserve(generators_amount);
-
- std::size_t lowest_bound{0};
- std::size_t generators_step{1000};
- std::size_t lower_bound_offset{1};
-
- generators_bounds[0] = Catch::Generators::random(lowest_bound, generators_step).get();
- generators.push_back(Catch::Generators::random(lowest_bound, generators_bounds[0]));
-
- // We use this one to group together values that are generated
- // from the same generator and to provide an index for that
- // generator to use for finding its associated probability.
- // Since our generators are defined by their upper bounds and
- // the collection of upper bounds is sorted, the first
- // encountered upper bound that is not less than the value
- // itself must be the least upper bound of the generator that
- // produced the value.
- // Then, the index of that upper bound must be the same as the
- // index of the producing generator and its associated
- // probability.
- auto find_index_of_producing_generator = [&generators_bounds](auto value) {
- return static_cast<std::size_t>(std::distance(
- generators_bounds.begin(),
- std::find_if(generators_bounds.begin(), generators_bounds.end(), [&value](auto element){ return value <= element; })
- ));
- };
-
- for (std::size_t index{1}; index < generators_amount; ++index) {
- generators_bounds[index] = Catch::Generators::random(generators_bounds[index - 1] + lower_bound_offset + 1, generators_bounds[index - 1] + lower_bound_offset + 1 + generators_step).get();
- generators.push_back(Catch::Generators::random(generators_bounds[index - 1] + lower_bound_offset, generators_bounds[index]));
- }
-
- AND_GIVEN("A probability of being chosen, in percentage, for each of the generators, such that the sum of the percentages is one hundred") {
- std::vector<double> probabilities = GENERATE_COPY(take(10, k_partition_of_r(100.0, generators_amount)));
-
- AND_GIVEN("A choosing generator for those generators based on the given probabilities") {
- auto choosing_generator = oneof(std::move(generators), probabilities);
-
- WHEN("A certain amount of values are generated from the choosing generator") {
- auto values = GENERATE_REF(take(1, chunk(10000, std::move(choosing_generator))));
-
- THEN("The distribution of elements for each generator approximately respects the weight that was given to it") {
- auto maybe_distribution_error{respects_distribution(
- std::move(values),
- find_index_of_producing_generator,
- [&probabilities](auto key){ return probabilities[key]; }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
- }
-
- AND_GIVEN("A choosing generator for those generators that will choose each generator with the same probability") {
- auto choosing_generator = uniform_oneof(std::move(generators));
-
- WHEN("A certain amount of values are generated from the choosing generator") {
- auto values = GENERATE_REF(take(1, chunk(10000, std::move(choosing_generator))));
-
- THEN("The distribution of elements approximates uniformity over the generators") {
- double probability{uniform_probability(generators_amount)};
-
- auto maybe_distribution_error{respects_distribution(
- std::move(values),
- find_index_of_producing_generator,
- [&probability](auto _){ (void)(_); return probability; }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
-
- AND_GIVEN("A choosing generator for those generators that will choose each generator such that each possible value has the same probability of being chosen") {
- // REMARK: We need to know the total amount of
- // unique values that can be generated by our
- // generators, so that we can construct an
- // appropriate distribution.
- // Since our generators are ranges defined by the
- // collection of upper bounds we can find their
- // length by finding the difference between
- // adjacent elements of the collection.
- //
- // Some more care must be taken to ensure tha the
- // correct amount is produced.
- // Since we need our ranges to be disjoint, we
- // apply a small offset from the element of the
- // upper bounds that is used as a lower bound,
- // since that upper bound is inclusive for the
- // range that precedes the one we are making the
- // calculation for.
- //
- // Furthermore, the first range is treated
- // specially.
- // As no range precedes it, it doesn't need any
- // offset to be applied.
- // Additionally, we implicitly use 0 as the first
- // lower bound, such that the length of the first
- // range is indeed equal to its upper bound.
- //
- // To account for this, we remove that offset from
- // the total amount for each range after the first
- // one and use the first upper bound as a seeding
- // value to account for the length of the first
- // range.
- std::vector<std::size_t> generators_cardinality(generators_amount, generators_bounds[0]);
-
- std::adjacent_difference(generators_bounds.begin(), generators_bounds.end(), generators_bounds.begin());
- std::transform(std::next(generators_cardinality.begin()), generators_cardinality.end(), std::next(generators_cardinality.begin()), [](auto element){ return element - 1; });
-
- std::size_t output_cardinality{std::accumulate(generators_cardinality.begin(), generators_cardinality.end(), std::size_t{0})};
-
- auto choosing_generator = uniformly_valued_oneof(std::move(generators), std::move(generators_cardinality));
-
- WHEN("A certain amount of values are generated from the choosing generator") {
- auto values = GENERATE_REF(take(1, chunk(10000, std::move(choosing_generator))));
-
- THEN("The distribution of elements approximates uniformity for each value") {
- double probability{uniform_probability(output_cardinality)};
-
- auto maybe_distribution_error{respects_distribution(
- std::move(values),
- [](auto value){ return value; },
- [&probability](auto _){ (void)(_); return probability; }
- )};
-
- REQUIRE_FALSE(maybe_distribution_error);
- }
- }
- }
- }
-}
-
-TEST_CASE("A generator with a weight of zero is never chosen when choosing between many generators", "[OneOf][Combinators][SpecialCase]") {
- auto excluded_value = GENERATE(take(100, random(0, 10000)));
-
- std::vector<Catch::Generators::GeneratorWrapper<int>> generators;
- generators.reserve(2);
- generators.emplace_back(Catch::Generators::random(excluded_value + 1, std::numeric_limits<int>::max()));
- generators.emplace_back(Catch::Generators::value(copy_value(excluded_value)));
-
- auto generated_value = GENERATE_REF(take(100, oneof(std::move(generators), std::vector{100.0, 0.0})));
-
- REQUIRE(generated_value != excluded_value);
-}
-
-TEST_CASE("The first element of the passed in generators are not lost", "[OneOf][Combinators][GeneratorFirstElement][SpecialCase]") {
- // REMARK: We want to test that, for each generator, the first
- // time it is chosen the first value is produced.
- // This is complicated because of the fact that OneOf chooses
- // random generators in a random order.
- // This means that some generators may never be chosen, never be
- // chosen more than once and so on.
- // Furthermore, this specific test is particularly important only
- // for finite generators or non-completely random, ordered,
- // infinite generators.
- // Additionally, we need to ensure that we test with multiple
- // generators, as this test is a consequence of a first bugged
- // implementation where only the first chosen generator respected
- // the first value, which would pass a test where a single
- // generator is used.
- //
- // This is non-trivial due to the randomized nature of OneOf.
- // It can be simplified if we express it in a non-deterministic
- // way and mark it as mayfail, where we can recognize with a good
- // certainty that the test is actually passing.
- //
- // To avoid having this flaky test, we approach it as follows:
- //
- // We provide some amount of infinite generators. Those generators
- // are ensured to produce one specific value as their first value
- // and then infinitely produce a different value.
- // We ensure that each generator that is provided produces unique
- // values, that is, no two generators produce a first value or 1 <
- // nth value that is equal to the one produced by another
- // generator.
- //
- // Then we pass those generators to oneof and generate enough
- // values such that at least one of the generators must have been
- // chosen twice or more, at random.
- //
- // We count the appearances of each value in the produced set.
- // Then, if a value that is generated by the 1 < nth choice of a
- // specific generator is encountered, we check that the first
- // value that the specific generator would produce is in the set
- // of values that were generated.
- // That is, if a generator has produced his non-first value, it
- // must have been chosen twice or more.
- // This in turn implies that the first time that the generator was
- // chosen, its first value was actually produced.
-
- struct IncreaseAfterFirst {
- std::size_t increase;
- bool first_application = true;
-
- std::size_t operator()(std::size_t value) {
- if (first_application) {
- first_application = false;
- return value;
- }
-
- return value + increase;
- }
- };
-
- std::size_t maximum_generator_amount{100};
- auto generators_amount = GENERATE_COPY(take(10, random(std::size_t{1}, maximum_generator_amount)));
-
- std::vector<Catch::Generators::GeneratorWrapper<std::size_t>> generators;
- generators.reserve(generators_amount);
-
- for (std::size_t index{0}; index < generators_amount; ++index) {
- generators.push_back(Catch::Generators::map(IncreaseAfterFirst{maximum_generator_amount}, cycle(Catch::Generators::value(copy_value(index)))));
- }
-
- auto values = GENERATE_REF(take(1, chunk(generators_amount + 1, uniform_oneof(std::move(generators)))));
- auto histogram{make_histogram(values.begin(), values.end(), [](auto e){ return e; })};
-
- for (std::size_t index{0}; index < generators_amount; ++index) {
- std::size_t second_value{index + maximum_generator_amount};
- histogram.try_emplace(second_value, 0);
-
- if (histogram[second_value] > 0) {
- REQUIRE(histogram.find(index) != histogram.end());
- }
- }
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/main.cpp b/tests/auto/qdoc/catch_generators/tests/main.cpp
deleted file mode 100644
index cec18afba..000000000
--- a/tests/auto/qdoc/catch_generators/tests/main.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#define CATCH_CONFIG_RUNNER
-#include <catch/catch.hpp>
-
-// A custom main was provided to avoid linking errors when using minGW
-// that were appearing in CI.
-// See https://github.com/catchorg/Catch2/issues/1287
-int main(int argc, char* argv[]) {
- return Catch::Session().run(argc, argv);
-}
diff --git a/tests/auto/qdoc/catch_generators/tests/utilities/semantics/catch_generator_handler.cpp b/tests/auto/qdoc/catch_generators/tests/utilities/semantics/catch_generator_handler.cpp
deleted file mode 100644
index 913646be5..000000000
--- a/tests/auto/qdoc/catch_generators/tests/utilities/semantics/catch_generator_handler.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include <catch/catch.hpp>
-
-#include "namespaces.h"
-#include "utilities/semantics/generator_handler.h"
-
-using namespace QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE;
-
-TEST_CASE(
- "Calling next 0 < n times and then calling get on a GeneratorHandler wrapping a generator behaves the same as only calling next (n-1) times and then get on the generator that is wrapped",
- "[GeneratorHandler][Utilities][Semantics][Generators]"
-) {
- auto n = GENERATE(take(100, random(1, 100)));
- auto generator_values = GENERATE_COPY(take(1, chunk(n, random(0, 100000))));
-
- auto generator_handler = handler(Catch::Generators::from_range(generator_values.begin(), generator_values.end()));
- auto generator{Catch::Generators::from_range(generator_values.begin(), generator_values.end())};
-
- generator_handler.next();
- for (int times{1}; times < n; ++times) {
- generator_handler.next();
- generator.next();
- }
-
- REQUIRE(generator_handler.get() == generator.get());
-}
diff --git a/tests/auto/qdoc/qdoc/CMakeLists.txt b/tests/auto/qdoc/qdoc/CMakeLists.txt
index 925290ecd..7e145ab30 100644
--- a/tests/auto/qdoc/qdoc/CMakeLists.txt
+++ b/tests/auto/qdoc/qdoc/CMakeLists.txt
@@ -15,8 +15,8 @@ qt_internal_add_test(tst_QDoc
${QDOC_SOURCE_DIRECTORY}/filesystem/fileresolver.cpp
INCLUDE_DIRECTORIES
${QDOC_INCLUDE_DIRECTORY}
- ../catch_generators/
LIBRARIES
Qt::QDocCatchPrivate
Qt::QDocCatchConversionsPrivate
+ Qt::QDocCatchGeneratorsPrivate
)
diff --git a/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_directorypath.cpp b/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_directorypath.cpp
index 5321e2619..31a45bfa4 100644
--- a/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_directorypath.cpp
+++ b/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_directorypath.cpp
@@ -7,7 +7,7 @@
#include <boundaries/filesystem/directorypath.h>
-#include <qdoc_catch_generators.h>
+#include <catch_generators/generators/path_generator.h>
#include <QFileInfo>
#include <QTemporaryDir>
diff --git a/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_filepath.cpp b/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_filepath.cpp
index 46481e4d6..957a13127 100644
--- a/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_filepath.cpp
+++ b/tests/auto/qdoc/qdoc/boundaries/filesystem/catch_filepath.cpp
@@ -7,7 +7,7 @@
#include <boundaries/filesystem/filepath.h>
-#include <qdoc_catch_generators.h>
+#include <catch_generators/generators/path_generator.h>
#include <QFileInfo>
#include <QTemporaryDir>
diff --git a/tests/auto/qdoc/qdoc/filesystem/catch_fileresolver.cpp b/tests/auto/qdoc/qdoc/filesystem/catch_fileresolver.cpp
index fca33debb..75774c9cc 100644
--- a/tests/auto/qdoc/qdoc/filesystem/catch_fileresolver.cpp
+++ b/tests/auto/qdoc/qdoc/filesystem/catch_fileresolver.cpp
@@ -7,7 +7,7 @@
#include <filesystem/fileresolver.h>
-#include <qdoc_catch_generators.h>
+#include <catch_generators/generators/path_generator.h>
#include <vector>
#include <algorithm>