File tddregister.h
File List > code_source > templat > include > TempLat > util > tdd > tddregister.h
Go to the documentation of this file
#ifndef TEMPLAT_UTIL_TDD_TDDREGISTER_H
#define TEMPLAT_UTIL_TDD_TDDREGISTER_H
/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
Released under the MIT license, see LICENSE.md. */
// File info: Main contributor(s): Wessel Valkenburg, Year: 2019
#include <cstddef>
#include <vector>
#include <tuple>
#include <iostream>
#include "TempLat/util/demangle.h"
#include "TempLat/util/tdd/tddcontainerbase.h"
#include "TempLat/util/tdd/tddmacros.h"
#include "TempLat/util/log/log.h"
#include "TempLat/util/log/saycomplete.h"
#ifdef HAVE_MPI
#include <mpi.h>
#endif
namespace TempLat
{
class TDDRegister
{
public:
// Put public methods here. These should change very little over time.
static void add(TDDContainerBase *ptr, const char *idName)
{
if (ptr != NULL && idName != NULL) {
theList().emplace_back(ptr, Demangle::demangle(idName), 0);
}
}
static ptrdiff_t run()
{
/* it's run time! */
// say << "Will perform " << theList().size() << " test" << (theList().size() > 1u ? "s" : "") <<
// ".\n";
for (auto &&it : theList()) {
#ifdef HAVE_MPI
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
const bool verbose = rank == 0;
#else
const bool verbose = true;
#endif
if (verbose) sayShort << "Starting tests for [" << std::get<1>(it) << "]\n";
#ifdef HAVE_MPI
MPI_Barrier(MPI_COMM_WORLD);
#endif
std::get<2>(it) = std::get<0>(it)->Test();
#ifdef HAVE_MPI
MPI_Barrier(MPI_COMM_WORLD);
#endif
if (verbose) sayShort << "Finished tests for [" << std::get<1>(it) << "]\n\n\n";
#ifdef HAVE_MPI
MPI_Barrier(MPI_COMM_WORLD);
#endif
}
return summarize();
}
static bool isSingleUnitTest() { return theList().size() == 1; }
private:
/* Put all member variables and private methods here. These may change arbitrarily. */
inline static std::vector<std::tuple<TDDContainerBase *, std::string, ptrdiff_t>> &theList()
{
static std::vector<std::tuple<TDDContainerBase *, std::string, ptrdiff_t>> theList;
return theList;
}
static constexpr size_t lineSize = 64;
static constexpr size_t nameSize = 48;
#ifdef HAVE_MPI
static ptrdiff_t summarize_MPI()
{
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
ptrdiff_t result = 0;
if (theList().size() > 0u) {
std::string line;
line.resize(lineSize, '-');
if (rank == 0) {
std::cerr << "Summary:\n";
std::cerr << line << "\n";
}
/* dumb, let's just do it twice, first only print succes, then show all failure. */
for (ptrdiff_t sucfail = 0; sucfail < 2; ++sucfail) {
for (auto &&it : theList()) {
ptrdiff_t mfailCount = std::get<2>(it);
// Gather the respective failCounts into an array so we can report on each rank's failures.
std::vector<int> allFailCounts(size);
MPI_Gather(&mfailCount, 1, MPI_INT, allFailCounts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
// Sum up the total fail count across all ranks.
ptrdiff_t totalFailCount = 0;
for (int i = 0; i < size; ++i) {
totalFailCount += allFailCounts[i];
}
// Report only on success or only on failure, depending on the value of sucfail.
if ((totalFailCount && !sucfail) || (!totalFailCount && sucfail)) continue;
result += totalFailCount;
// Only rank 0 reports.
if (rank != 0) continue;
std::stringstream sstream;
sstream << "[" + std::get<1>(it) + "]\n";
for (int r = 0; r < size; ++r) {
auto str = " Rank " + std::to_string(r);
str.resize(nameSize, ' ');
sstream << str << " - ";
if (allFailCounts[r] > 0) {
std::string plurals = allFailCounts[r] == 1 ? "" : "s";
sstream << allFailCounts[r] << " fail" << plurals << ".\n";
} else {
sstream << "all passed.\n";
}
}
if (totalFailCount > 0)
std::cerr << KRED << sstream.str() << KRESET;
else
std::cerr << sstream.str();
}
}
if (rank == 0) {
std::string tot(" Total:");
tot.resize(32, ' ');
std::cerr << line << "\n";
std::cerr << tot << " - ";
if (result > 0) {
std::cerr << result << " fails.\n";
} else {
std::cerr << "all passed.\n";
}
}
}
MPI_Barrier(MPI_COMM_WORLD);
return result;
}
#endif
static ptrdiff_t summarize()
{
#ifdef HAVE_MPI
return summarize_MPI();
#endif
ptrdiff_t result = 0;
if (theList().size() > 0u) {
std::string line;
line.resize(lineSize, '-');
std::string emptyName;
emptyName.resize(nameSize, ' ');
emptyName = "\n" + emptyName;
std::cerr << "Summary:\n";
std::cerr << line << "\n";
/* dumb, let's just do it twice, first only print succes, then show all failure. */
for (ptrdiff_t sucfail = 0; sucfail < 2; ++sucfail) {
for (auto &&it : theList()) {
ptrdiff_t failCount = std::get<2>(it);
if ((failCount && !sucfail) || (!failCount && sucfail)) continue;
std::stringstream sstream;
auto str = "[" + std::get<1>(it) + "]";
if (str.size() <= nameSize)
str.resize(nameSize, ' ');
else
str += emptyName;
sstream << str << " - ";
if (failCount > 0) {
result += failCount;
std::string plurals = failCount == 1 ? "" : "s";
sstream << failCount << " fail" << plurals << ".\n";
} else {
sstream << "all passed.\n";
}
if (failCount)
std::cerr << KRED << sstream.str() << KRESET;
else
std::cerr << sstream.str();
}
}
std::string tot(" Total:");
tot.resize(32, ' ');
std::cerr << line << "\n";
std::cerr << tot << " - ";
if (result > 0) {
std::cerr << result << " fails.\n";
} else {
std::cerr << "all passed.\n";
}
}
return result;
}
public:
template <typename TestObjectUnknownHere> static inline void Test(TestObjectUnknownHere &tdd);
};
} // namespace TempLat
#endif