Improve odr test (#59)

* rename link test to odr test and check odr test completeness
* added convenience header for algorithm
* added minimal docs for axis.hpp, accumulators.hpp, algorithm.hpp
* temporarily remove display.hpp (will return in another patch)
This commit is contained in:
Hans Dembinski 2019-10-12 15:12:53 +02:00 committed by GitHub
parent 6ad7d5bfea
commit 05c1bbfac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 169 additions and 552 deletions

View File

@ -29,26 +29,37 @@ matrix:
# earliest supported gcc version
- name: "gcc-5: default and restricted"
script:
- ../../b2 -j2 toolset=gcc-5 cxxstd=latest warnings-as-errors=on examples test test//failure &&
../../b2 -j2 toolset=gcc-5 cxxstd=latest warnings-as-errors=on exception-handling=off rtti=off test//minimal
../../b2 -j2 toolset=gcc-5 cxxstd=latest warnings-as-errors=on examples test//all &&
../../b2 -j2 toolset=gcc-5 cxxstd=latest warnings-as-errors=on exception-handling=off rtti=off test//minimal
- name: "clang: sanitizers"
sudo: required # by leak sanitizer
script:
- UBSAN_OPTIONS=print_stacktrace=1
LSAN_OPTIONS=verbosity=1:log_threads=1
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1
../../b2 -j2 toolset=clang cxxstd=14 variant=histogram_ubasan warnings-as-errors=on
UBSAN_OPTIONS=print_stacktrace=1
LSAN_OPTIONS=verbosity=1:log_threads=1
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1
../../b2 -j2 toolset=clang cxxstd=14 variant=histogram_ubasan warnings-as-errors=on
test//all
- name: "gcc-8: c++latest and coverage"
- name: "gcc-8: cxxstd=latest and coverage"
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-8
script:
- ../../b2 -j2 toolset=gcc-8 cxxstd=latest warnings-as-errors=on coverage=on examples test test//failure
# don't run examples, because full coverage must come from tests alone
- ../../b2 -j2 toolset=gcc-8 cxxstd=latest warnings-as-errors=on coverage=on test//all
- GCOV=gcov-8 tools/cov.sh
- name: "gcc-9: cxxstd=latest"
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-9
script:
../../b2 -j2 toolset=gcc-9 cxxstd=latest warnings-as-errors=on
examples test//all
before_script:
# clone minimal set of Boost libraries
- test "$TRAVIS_BRANCH" == "master" && BRANCH=master || BRANCH=develop

View File

@ -9,7 +9,7 @@
/**
\file boost/histogram.hpp
Includes all standard headers of the Boost.histogram library.
Includes all standard headers of the Boost.Histogram library.
Extra headers not automatically included are:
- [boost/histogram/ostream.hpp][1]
@ -25,14 +25,8 @@
[5]: histogram/reference.html#header.boost.histogram.display_hpp
*/
#include <boost/histogram/accumulators/mean.hpp>
#include <boost/histogram/accumulators/sum.hpp>
#include <boost/histogram/accumulators/thread_safe.hpp>
#include <boost/histogram/accumulators/weighted_mean.hpp>
#include <boost/histogram/accumulators/weighted_sum.hpp>
#include <boost/histogram/algorithm/project.hpp>
#include <boost/histogram/algorithm/reduce.hpp>
#include <boost/histogram/algorithm/sum.hpp>
#include <boost/histogram/accumulators.hpp>
#include <boost/histogram/algorithm.hpp>
#include <boost/histogram/axis.hpp>
#include <boost/histogram/histogram.hpp>
#include <boost/histogram/indexed.hpp>

View File

@ -7,6 +7,16 @@
#ifndef BOOST_HISTOGRAM_ACCUMULATORS_HPP
#define BOOST_HISTOGRAM_ACCUMULATORS_HPP
/**
\file boost/accumulators.hpp
Includes all accumulator headers of the Boost.Histogram library.
Extra header not automatically included:
- [boost/histogram/accumulators/ostream.hpp][1]
[1]: histogram/reference.html#header.boost.histogram.accumulators.ostream_hpp
*/
#include <boost/histogram/accumulators/mean.hpp>
#include <boost/histogram/accumulators/sum.hpp>
#include <boost/histogram/accumulators/thread_safe.hpp>

View File

@ -0,0 +1,19 @@
// Copyright 2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_HISTOGRAM_ALGORITHM_HPP
#define BOOST_HISTOGRAM_ALGORITHM_HPP
/**
\file boost/algorithm.hpp
Includes all algorithm headers of the Boost.Histogram library.
*/
#include <boost/histogram/algorithm/project.hpp>
#include <boost/histogram/algorithm/reduce.hpp>
#include <boost/histogram/algorithm/sum.hpp>
#endif

View File

@ -7,6 +7,16 @@
#ifndef BOOST_HISTOGRAM_AXIS_HPP
#define BOOST_HISTOGRAM_AXIS_HPP
/**
\file boost/axis.hpp
Includes all axis headers of the Boost.Histogram library.
Extra header not automatically included:
- [boost/histogram/axis/ostream.hpp][1]
[1]: histogram/reference.html#header.boost.histogram.axis.ostream_hpp
*/
#include <boost/histogram/axis/category.hpp>
#include <boost/histogram/axis/integer.hpp>
#include <boost/histogram/axis/regular.hpp>

View File

@ -1,250 +0,0 @@
// Copyright (c) 2019 Przemyslaw Bartosik
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_HISTOGRAM_DISPLAY_HPP
#define BOOST_HISTOGRAM_DISPLAY_HPP
#include <boost/histogram.hpp>
#include <boost/histogram/accumulators/ostream.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/fwd.hpp>
#include <algorithm> // max_element
#include <cmath> // floor, pow
#include <iomanip> // setw
#include <iosfwd>
#include <iostream> // cout
#include <limits> // infinity
namespace boost {
namespace histogram {
namespace detail {
struct display_settings {
const unsigned int default_width = 80; // default witdth of visualization
const unsigned int min_width = 40; // min width of visualization
const unsigned int max_width = 120; // max width of visualization
unsigned int histogram_width = 60; // default graph width
unsigned int histogram_shift = 0; // labels and values width
const double max_bin_coefficient = 0.95; // 95% of histogram_width
const unsigned int bounds_prec = 1; // precision of upper and lower bounds
const unsigned int values_prec = 0; // precision of values
const unsigned int margin = 2; // margin from left edge
} d_s;
template <class Histogram>
void stream_lower_bound(std::ostream& out,
typename indexed_range<const Histogram>::range_iterator ri,
const unsigned int l_bounds_width = 0) {
if (l_bounds_width != 0)
out << std::right << std::setw(l_bounds_width);
out << std::fixed << std::setprecision(d_s.bounds_prec) << ri->bin().lower();
}
template <class Histogram>
void stream_upper_bound(std::ostream& out,
typename indexed_range<const Histogram>::range_iterator ri,
const unsigned int u_bounds_width = 0) {
if (u_bounds_width != 0)
out << std::right << std::setw(u_bounds_width);
out << std::fixed << std::setprecision(d_s.bounds_prec) << ri->bin().upper();
}
template <class Histogram>
void stream_value(std::ostream& out,
typename indexed_range<const Histogram>::range_iterator ri,
const unsigned int column_width = 0) {
if (column_width != 0)
out << std::left << std::setw(column_width);
out << std::fixed << std::setprecision(d_s.values_prec) << *(ri);
}
template <class Histogram>
void stream_label(std::ostream& out,
typename indexed_range<const Histogram>::range_iterator ri,
const unsigned int l_bounds_width,
const unsigned int u_bounds_width) {
char parenthesis = ' ';
if (std::isfinite(ri->bin().upper()))
parenthesis = ')';
else
parenthesis = ']';
out << '[';
stream_lower_bound<Histogram>(out, ri, l_bounds_width);
out << ", ";
stream_upper_bound<Histogram>(out, ri, u_bounds_width);
out << parenthesis;
}
unsigned int get_num_of_chars(std::ostream& out) {
auto result = static_cast<unsigned int>(out.tellp());
out.clear();
out.seekp(0); // reset
return result;
}
template <class Histogram, class Getter>
unsigned int get_max_width(const Histogram& h, const Getter& streamFnPtr) {
auto data = indexed(h, coverage::all);
unsigned int max_length = 0;
unsigned int temp = 0;
std::ostringstream os;
for (auto ri = data.begin(); ri != data.end(); ++ri) {
streamFnPtr(os, ri, 0);
temp = get_num_of_chars(os);
if (temp > max_length)
max_length = temp;
}
return max_length;
}
void stream_line(std::ostream& out,
const unsigned int num,
const char c = '*',
bool complete = true) {
unsigned int i = 0;
for (; i < num; ++i) out << c;
if (complete == true) { //|****<---->|
for (; i < d_s.histogram_width; ++i) out << ' ';
}
}
template <class Histogram>
unsigned int calculate_scale_factor(typename indexed_range<const Histogram>::range_iterator ri,
const double& max_value) {
double result = 0;
if (max_value != 0) {
const double longest_bin = d_s.max_bin_coefficient * d_s.histogram_width;
result = *ri * longest_bin / max_value;
}
return std::lround(result);
}
template <class Histogram>
void stream_histogram_line(std::ostream& out,
typename indexed_range<const Histogram>::range_iterator ri,
const double& max_value) {
const auto scaled_value = calculate_scale_factor<Histogram>(ri, max_value);
out << "|";
stream_line(out, scaled_value);
out << '|';
}
void stream_external_line(std::ostream& out) {
stream_line(out, d_s.histogram_shift, ' ', false);
out << "+";
stream_line(out, d_s.histogram_width, '-');
out << '+';
}
template <class Histogram>
void draw_histogram(std::ostream& out,
const Histogram& h,
const unsigned int u_bounds_width,
const unsigned int l_bounds_width,
const unsigned int values_width) {
auto data = indexed(h, coverage::all);
const auto max_v = *std::max_element(h.begin(), h.end());
out << "\n";
stream_external_line(out);
out << "\n";
for (auto it = data.begin(); it != data.end(); ++it) {
stream_line(out, d_s.margin, ' ', false);
stream_label<Histogram>(out, it, l_bounds_width, u_bounds_width);
out << " ";
stream_value<Histogram>(out, it, values_width);
out << " ";
stream_histogram_line<Histogram>(out, it, max_v);
out << "\n";
}
stream_external_line(out);
out << "\n\n";
}
unsigned int adjust_histogram_width(unsigned int terminal_width) {
const auto frame = 2; // | |
if (terminal_width < d_s.min_width)
terminal_width = d_s.min_width;
else if (terminal_width > d_s.max_width)
terminal_width = d_s.max_width;
return terminal_width - frame - d_s.histogram_shift;
}
template <class Histogram>
void display_histogram(std::ostream& out,
const Histogram& h,
const unsigned int terminal_width = d_s.default_width) {
const auto additional_offset = 7; // 7 white characters
const auto l_bounds_width = get_max_width(h, stream_lower_bound<Histogram>);
const auto u_bounds_width = get_max_width(h, stream_upper_bound<Histogram>);
const auto values_width = get_max_width(h, stream_value<Histogram>);
d_s.histogram_shift = l_bounds_width + u_bounds_width + values_width +
additional_offset + d_s.margin;
d_s.histogram_width = adjust_histogram_width(terminal_width);
draw_histogram(out, h, u_bounds_width, l_bounds_width, values_width);
}
template <class Histogram>
void old_style_ostream(std::ostream& os, const Histogram& h) {
if (os.width() != 0)
os.width(0); // ignore setw
os << "\n";
stream_line(os, d_s.margin, ' ', false);
os << "histogram(";
unsigned n = 0;
h.for_each_axis([&](const auto& a) {
if (h.rank() > 1) os << "\n ";
stream_line(os, d_s.margin, ' ', false);
os << a;
if (++n < h.rank()) os << ",";
});
os << (h.rank() > 1 ? "\n" : ")");
stream_line(os, d_s.margin, ' ', false);
os << ")\n";
}
template <class Histogram>
void new_style_ostream(std::ostream& os, const Histogram& h) {
const auto exp_width = static_cast<unsigned int>(os.width());
if (exp_width == 0)
display_histogram(os, h);
else {
os.width(0); // reset
display_histogram(os, h, exp_width);
}
}
} // ns detail
template <typename CharT, typename Traits, typename A, typename S>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const histogram<A, S>& h) {
if (h.rank() == 1)
detail::new_style_ostream(os, h);
else
detail::old_style_ostream(os, h);
return os;
}
} // ns histogram
} // ns boost
#endif

View File

@ -1,4 +1,5 @@
// Copyright 2015-2017 Hans Dembinski
// Copyright 2015-2019 Hans Dembinski
// Copyright (c) 2019 Przemyslaw Bartosik
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@ -7,10 +8,16 @@
#ifndef BOOST_HISTOGRAM_OSTREAM_HPP
#define BOOST_HISTOGRAM_OSTREAM_HPP
#include <algorithm> // max_element
#include <boost/histogram.hpp>
#include <boost/histogram/accumulators/ostream.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/fwd.hpp>
#include <cmath> // floor, pow
#include <iomanip> // setw
#include <iosfwd>
#include <iostream> // cout
#include <limits> // infinity
/**
\file boost/histogram/ostream.hpp

View File

@ -5,6 +5,7 @@
boost_test(SOURCES check_cmake_version.cpp ARGUMENTS ${PROJECT_VERSION}
LIBRARIES Boost::core Boost::config)
# checks that b2 and cmake are in sync
add_test(NAME check_build_system COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/check_build_system.py)
# keep in sync with Jamfile, this should be automatized...
@ -78,8 +79,6 @@ boost_test(TYPE run SOURCES detail_static_if_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES detail_tuple_slice_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES display_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES histogram_custom_axis_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES histogram_dynamic_test.cpp
@ -102,8 +101,6 @@ boost_test(TYPE run SOURCES unlimited_storage_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES utility_test.cpp
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE link SOURCES link_2_test.cpp link_1_test.cpp
LIBRARIES Boost::histogram Boost::core)
if (cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
boost_test(TYPE run SOURCES deduction_guides_test.cpp
@ -119,6 +116,8 @@ if (Threads_FOUND)
endif()
## No cmake support yet
# boost_test(TYPE link SOURCES odr_main_test.cpp odr_test.cpp
# LIBRARIES Boost::histogram Boost::core)
# boost_test(TYPE run SOURCES boost_accumulators_support_test.cpp
# LIBRARIES Boost::histogram Boost::core Boost::accumulators)
# boost_test(TYPE run SOURCES boost_range_support_test.cpp

View File

@ -6,11 +6,13 @@
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
import python ;
import os ;
import regex ;
import testing ;
import ../../config/checks/config : requires ;
path-constant THIS_PATH : . ;
project
@ -21,6 +23,13 @@ project
]
;
# Verify One Definition Rule by linking two object files which include everything
testing.make-test run-pyd : odr_test.py : : check_odr_test ;
alias odr :
check_odr_test
[ link odr_main_test.cpp odr_test.cpp ]
;
alias cxx14 :
[ run accumulators_test.cpp ]
[ run algorithm_project_test.cpp ]
@ -61,7 +70,6 @@ alias cxx14 :
[ run storage_adaptor_test.cpp ]
[ run unlimited_storage_test.cpp ]
[ run utility_test.cpp ]
[ run display_test.cpp ]
;
alias cxx17 :
@ -69,11 +77,6 @@ alias cxx17 :
[ requires cpp_deduction_guides ]
;
# Verify that the compile succeeds when linking (missing inline detection)
alias compiles :
[ link link_2_test.cpp link_1_test.cpp ]
;
# check that useful error messages are produced when library is used incorrectly
alias failure :
[ compile-fail axis_category_fail0.cpp ]
@ -117,13 +120,20 @@ alias libserial :
<link>static <warnings>off <rtti>on
;
# skipping "failure", since expected failure messages during debugging are confusing
alias all : cxx14 cxx17 compiles threading accumulators range units serialization ;
alias minimal : cxx14 cxx17 compiles threading ;
# for builds without optional boost dependencies
alias minimal : odr cxx14 cxx17 failure threading ;
# all tests
alias all : minimal accumulators range units serialization ;
# all except "failure", because it is distracting during development
alias develop : odr cxx14 cxx17 threading accumulators range units serialization ;
explicit minimal ;
explicit all ;
explicit odr ;
explicit cxx14 ;
explicit cxx17 ;
explicit compiles;
explicit failure ;
explicit threading ;
explicit accumulators ;

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
#include <boost/histogram.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/ostream.hpp>
// All files should be include above
// Simple do-nothing function, used to keep the compiler from throwing away this file
int do_nothing() { return 7; }

View File

@ -1,24 +0,0 @@
// Copyright 2018 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/ostream.hpp>
// All files should be included above
int do_nothing();
// Verifies there are no functions with missing inline
int main() {
int a = do_nothing();
BOOST_TEST_EQ(a, 7);
return boost::report_errors();
}

10
test/odr_main_test.cpp Normal file
View File

@ -0,0 +1,10 @@
// Copyright 2019 Henry Schreiner, Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// include all headers again
#include "odr_test.cpp"
int main() { return 0; }

12
test/odr_test.cpp Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2019 Henry Schreiner, Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// include all Boost.Histogram header here
#include <boost/histogram.hpp>
#include <boost/histogram/accumulators.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/ostream.hpp>
#include <boost/histogram/serialization.hpp>

54
test/odr_test.py Normal file
View File

@ -0,0 +1,54 @@
# Copyright 2019 Hans Dembinski, Henry Schreiner
#
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt
# or copy at http://www.boost.org/LICENSE_1_0.txt)
import os
import sys
import re
this_path = os.path.dirname(__file__)
all_headers = set()
include_path = os.path.join(this_path, "..", "include")
for root, dirs, files in os.walk(include_path):
for fn in files:
fn = os.path.join(root, fn)
assert fn.startswith(include_path)
fn = fn[len(include_path) + 1 :]
all_headers.add(fn)
def get_headers(filename):
with open(filename) as f:
for hdr in re.findall('^#include [<"]([^>"]+)[>"]', f.read(), re.MULTILINE):
if not hdr.startswith("boost/histogram"):
continue
yield hdr.replace("/", os.path.sep) # adapt the paths for Windows
included_headers = set()
unread_headers = set()
for hdr in get_headers(os.path.join(this_path, "odr_test.cpp")):
unread_headers.add(hdr)
while unread_headers:
included_headers.update(unread_headers)
for hdr in tuple(unread_headers): # copy needed because unread_headers is modified
unread_headers.remove(hdr)
for hdr2 in get_headers(os.path.join(include_path, hdr)):
if hdr2 not in included_headers:
unread_headers.add(hdr2)
diff = sorted(all_headers - set(included_headers))
if not diff:
sys.exit(0)
print("Header not included in odr_test.cpp:")
for fn in diff:
print(fn)
sys.exit(1)

View File

@ -36,6 +36,7 @@ void load_xml(const std::string& filename, T& t) {
char line[128];
do {
ifs.getline(line, 128);
BOOST_ASSERT(std::strlen(line) < 127);
} while (!ifs.fail() && !ifs.eof() && std::strstr(line, "-->") == nullptr);
boost::archive::xml_iarchive ia(ifs);
ia >> boost::serialization::make_nvp("item", t);