The -B, -G, -V reports now show rounding amounts

This way, if the running total is off by a penny or two due to rounding
of one or more commodities in the account, the user will see it.

This commit also reorganizes the testing code a bit, which I did after
adding the ninth test series (ConfirmTests), to validate the new
rounding code.
This commit is contained in:
John Wiegley 2009-02-26 00:56:47 -04:00
parent 74e569e220
commit d58797e98c
22 changed files with 294 additions and 423 deletions

View file

@ -240,16 +240,16 @@ endif
TESTS =
if HAVE_PYTHON
TESTS += RegressionTests BaselineTests
TESTS += RegressTests BaselineTests ConfirmTests
endif
if HAVE_CPPUNIT
TESTS += \
util_tests \
math_tests \
expr_tests \
data_tests \
report_tests
UtilTests \
MathTests \
ExprTests \
DataTests \
ReportTests
endif
if HAVE_BOOST_PYTHON
@ -258,22 +258,22 @@ endif
check_PROGRAMS = $(TESTS)
util_tests_SOURCES = \
UtilTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/util_tests.cc \
test/UtilTests.cc \
test/unit/t_utils.cc \
test/unit/t_utils.h \
test/unit/t_times.cc \
test/unit/t_times.h
util_tests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
util_tests_LDADD = libledger_util.la -lcppunit
UtilTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
UtilTests_LDADD = libledger_util.la -lcppunit
math_tests_SOURCES = \
MathTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/math_tests.cc \
test/MathTests.cc \
test/unit/t_commodity.cc \
test/unit/t_commodity.h \
test/unit/t_amount.cc \
@ -281,41 +281,41 @@ math_tests_SOURCES = \
test/unit/t_balance.cc \
test/unit/t_balance.h
math_tests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
math_tests_LDADD = libledger_math.la $(util_tests_LDADD)
MathTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
MathTests_LDADD = libledger_math.la $(UtilTests_LDADD)
expr_tests_SOURCES = \
ExprTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/expr_tests.cc \
test/ExprTests.cc \
test/unit/t_expr.cc \
test/unit/t_expr.h
expr_tests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
expr_tests_LDADD = libledger_expr.la $(math_tests_LDADD)
ExprTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
ExprTests_LDADD = libledger_expr.la $(MathTests_LDADD)
data_tests_SOURCES = \
DataTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/data_tests.cc
test/DataTests.cc
data_tests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
data_tests_LDADD = libledger_data.la $(expr_tests_LDADD)
DataTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
DataTests_LDADD = libledger_data.la $(ExprTests_LDADD)
report_tests_SOURCES = \
ReportTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/report_tests.cc
test/ReportTests.cc
report_tests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
report_tests_LDADD = libledger_report.la $(data_tests_LDADD)
ReportTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
ReportTests_LDADD = libledger_report.la $(DataTests_LDADD)
all_tests_sources = \
$(util_tests_SOURCES) \
$(math_tests_SOURCES) \
$(expr_tests_SOURCES) \
$(data_tests_SOURCES) \
$(report_tests_SOURCES)
$(UtilTests_SOURCES) \
$(MathTests_SOURCES) \
$(ExprTests_SOURCES) \
$(DataTests_SOURCES) \
$(ReportTests_SOURCES)
PyUnitTests_SOURCES = test/PyUnitTests.py
@ -358,31 +358,39 @@ PyUnitTests: $(srcdir)/test/PyUnitTests.py \
| sed "s/%builddir%/$(ESC_builddir)/g" > $@
chmod 755 $@
RegressionTests_SOURCES = test/regress.py
RegressTests_SOURCES = test/RegressTests.py
EXTRA_DIST += test/regress test/convert.py
RegressionTests: $(srcdir)/test/regress.py
echo "$(PYTHON) $(srcdir)/test/regress.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/regress" > $@
RegressTests: $(srcdir)/test/RegressTests.py
echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/regress" > $@
chmod 755 $@
BaselineTests_SOURCES = test/regress.py
BaselineTests_SOURCES = test/RegressTests.py
EXTRA_DIST += test/baseline
BaselineTests: $(srcdir)/test/regress.py
echo "$(PYTHON) $(srcdir)/test/regress.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/baseline" > $@
BaselineTests: $(srcdir)/test/RegressTests.py
echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/baseline" > $@
chmod 755 $@
FULLCHECK=$(srcdir)/tools/fullcheck
ConfirmTests_SOURCES = test/ConfirmTests.py
EXTRA_DIST += test/input
ConfirmTests: $(srcdir)/test/ConfirmTests.py
echo "$(PYTHON) $(srcdir)/test/ConfirmTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/input" > $@
chmod 755 $@
FULLCHECK=$(srcdir)/test/fullcheck.sh
if HAVE_CPPUNIT
fullcheck: $(TESTS)
sh $(FULLCHECK) $(top_builddir)/util_tests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/math_tests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/expr_tests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/data_tests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/report_tests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/UtilTests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/MathTests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/ExprTests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/DataTests$(EXEEXT) --verify
sh $(FULLCHECK) $(top_builddir)/ReportTests$(EXEEXT) --verify
else
fullcheck: check
@test 1 -eq 1

View file

@ -196,6 +196,10 @@ namespace {
return long(account.depth);
}
value_t ignore(account_t&) {
return false;
}
value_t get_depth_spacer(account_t& account)
{
std::size_t depth = 0;
@ -259,6 +263,11 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
if (name == "total")
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
case 'u':
if (name == "use_direct_amount")
return WRAP_FUNCTOR(get_wrapper<&ignore>);
break;
}
return NULL;

View file

@ -79,9 +79,12 @@ post_handler_ptr chain_post_handlers(report_t& report,
// the running total unpredictably.
if (report.HANDLED(revalued))
handler.reset(new changed_value_posts
(handler, report.HANDLED(revalued_total_) ?
(handler,
report.HANDLER(display_amount_).expr,
report.HANDLED(revalued_total_) ?
report.HANDLER(revalued_total_).expr :
report.HANDLER(display_total_).expr,
report.HANDLER(display_total_).expr,
report, report.HANDLED(revalued_only)));
// calc_posts computes the running total. When this appears will

View file

@ -213,14 +213,17 @@ void calc_posts::operator()(post_t& post)
}
namespace {
void handle_value(const value_t& value,
account_t * account,
xact_t * xact,
unsigned int flags,
std::list<post_t>& temps,
item_handler<post_t>& handler,
const date_t& date = date_t(),
const value_t& total = value_t())
typedef function<void (post_t *)> post_functor_t;
void handle_value(const value_t& value,
account_t * account,
xact_t * xact,
std::list<post_t>& temps,
item_handler<post_t>& handler,
const date_t& date = date_t(),
const value_t& total = value_t(),
const bool direct_amount = false,
const optional<post_functor_t>& functor = none)
{
temps.push_back(post_t(account));
post_t& post(temps.back());
@ -259,7 +262,7 @@ namespace {
case value_t::BALANCE:
case value_t::SEQUENCE:
xdata.value = temp;
flags |= POST_EXT_COMPOUND;
xdata.add_flags(POST_EXT_COMPOUND);
break;
case value_t::DATETIME:
@ -272,8 +275,13 @@ namespace {
if (! total.is_null())
xdata.total = total;
if (flags)
xdata.add_flags(flags);
if (direct_amount)
xdata.add_flags(POST_EXT_DIRECT_AMT);
if (functor)
(*functor)(&post);
DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
handler(post);
}
@ -314,7 +322,7 @@ void collapse_posts::report_subtotal()
earliest_date : last_xact->_date);
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
handle_value(subtotal, &totals_account, &xact, 0, post_temps, *handler);
handle_value(subtotal, &totals_account, &xact, post_temps, *handler);
}
component_posts.clear();
@ -374,7 +382,7 @@ void related_posts::flush()
item_handler<post_t>::flush();
}
void changed_value_posts::output_diff(post_t * post, const date_t& date)
void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
{
if (is_valid(date))
post->xdata().date = date;
@ -391,36 +399,80 @@ void changed_value_posts::output_diff(post_t * post, const date_t& date)
post->xdata().date = date_t();
DEBUG("filter.changed_value",
"output_diff(last_balance) = " << last_balance);
"output_revaluation(last_balance) = " << last_total);
DEBUG("filter.changed_value",
"output_diff(repriced_total) = " << repriced_total);
"output_revaluation(repriced_total) = " << repriced_total);
if (value_t diff = repriced_total - last_balance) {
DEBUG("filter.changed_value", "output_diff(strip(diff)) = "
<< diff.strip_annotations(report.what_to_keep()));
if (! last_total.is_null()) {
if (value_t diff = repriced_total - last_total) {
DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = "
<< diff.strip_annotations(report.what_to_keep()));
xact_temps.push_back(xact_t());
xact_t& xact = xact_temps.back();
xact.payee = _("Commodities revalued");
xact._date = is_valid(date) ? date : post->date();
xact_temps.push_back(xact_t());
xact_t& xact = xact_temps.back();
xact.payee = _("Commodities revalued");
xact._date = is_valid(date) ? date : post->date();
handle_value(diff, &revalued_account, &xact, POST_EXT_NO_TOTAL,
post_temps, *handler, *xact._date, repriced_total);
handle_value(diff, &revalued_account, &xact, post_temps, *handler,
*xact._date, repriced_total, false,
optional<post_functor_t>
(bind(&changed_value_posts::output_rounding, this, _1)));
}
}
}
void changed_value_posts::output_rounding(post_t * post)
{
bind_scope_t bound_scope(report, *post);
value_t new_display_total(display_total_expr.calc(bound_scope));
DEBUG("filter.changed_value.rounding",
"rounding.new_display_total = " << new_display_total);
if (! last_display_total.is_null()) {
if (value_t repriced_amount = display_amount_expr.calc(bound_scope)) {
DEBUG("filter.changed_value.rounding",
"rounding.repriced_amount = " << repriced_amount);
value_t precise_display_total(new_display_total.truncated() -
repriced_amount.truncated());
DEBUG("filter.changed_value.rounding",
"rounding.precise_display_total = " << precise_display_total);
DEBUG("filter.changed_value.rounding",
"rounding.last_display_total = " << last_display_total);
if (value_t diff = precise_display_total - last_display_total) {
DEBUG("filter.changed_value.rounding",
"rounding.diff = " << diff);
xact_temps.push_back(xact_t());
xact_t& xact = xact_temps.back();
xact.payee = _("Commodity rounding");
xact._date = post->date();
handle_value(diff, &rounding_account, &xact, post_temps,
*handler, *xact._date, precise_display_total, true);
}
}
}
last_display_total = new_display_total;
}
void changed_value_posts::operator()(post_t& post)
{
if (last_post)
output_diff(last_post, post.date());
output_revaluation(last_post, post.date());
if (changed_values_only)
post.xdata().add_flags(POST_EXT_DISPLAYED);
output_rounding(&post);
item_handler<post_t>::operator()(post);
bind_scope_t bound_scope(report, post);
last_balance = total_expr.calc(bound_scope);
last_total = total_expr.calc(bound_scope);
last_post = &post;
}
@ -462,8 +514,8 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
xact._date = range_start;
foreach (values_map::value_type& pair, values)
handle_value(pair.second.value, pair.second.account, &xact, 0,
post_temps, *handler);
handle_value(pair.second.value, pair.second.account, &xact, post_temps,
*handler);
values.clear();
}
@ -581,8 +633,8 @@ void posts_as_equity::report_subtotal()
value_t total = 0L;
foreach (values_map::value_type& pair, values) {
handle_value(pair.second.value, pair.second.account, &xact, 0,
post_temps, *handler);
handle_value(pair.second.value, pair.second.account, &xact, post_temps,
*handler);
total += pair.second.value;
}
values.clear();

View file

@ -449,12 +449,16 @@ class changed_value_posts : public item_handler<post_t>
// This filter requires that calc_posts be used at some point
// later in the chain.
expr_t display_amount_expr;
expr_t total_expr;
expr_t display_total_expr;
report_t& report;
bool changed_values_only;
post_t * last_post;
value_t last_balance;
value_t last_total;
value_t last_display_total;
account_t revalued_account;
account_t rounding_account;
std::list<xact_t> xact_temps;
std::list<post_t> post_temps;
@ -463,14 +467,19 @@ class changed_value_posts : public item_handler<post_t>
public:
changed_value_posts(post_handler_ptr handler,
const expr_t& _display_amount_expr,
const expr_t& _total_expr,
const expr_t& _display_total_expr,
report_t& _report,
bool _changed_values_only)
: item_handler<post_t>(handler), total_expr(_total_expr),
report(_report), changed_values_only(_changed_values_only),
last_post(NULL), revalued_account(NULL, _("<Revalued>")) {
: item_handler<post_t>(handler),
display_amount_expr(_display_amount_expr), total_expr(_total_expr),
display_total_expr(_display_total_expr), report(_report),
changed_values_only(_changed_values_only), last_post(NULL),
revalued_account(NULL, _("<Revalued>")),
rounding_account(NULL, _("<Rounding>")){
TRACE_CTOR(changed_value_posts,
"post_handler_ptr, const expr_t&, report_t&, bool");
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
}
virtual ~changed_value_posts() {
TRACE_DTOR(changed_value_posts);
@ -479,13 +488,14 @@ public:
virtual void flush() {
if (last_post && last_post->date() <= CURRENT_DATE()) {
output_diff(last_post, CURRENT_DATE());
output_revaluation(last_post, CURRENT_DATE());
last_post = NULL;
}
item_handler<post_t>::flush();
}
void output_diff(post_t * post, const date_t& current);
void output_revaluation(post_t * post, const date_t& current);
void output_rounding(post_t * post);
virtual void operator()(post_t& post);
};

View file

@ -158,6 +158,10 @@ namespace {
}
}
value_t get_use_direct_amount(post_t& post) {
return post.has_xdata() && post.xdata().has_flags(POST_EXT_DIRECT_AMT);
}
value_t get_commodity(post_t& post) {
return string_value(post.amount.commodity().symbol());
}
@ -282,6 +286,11 @@ expr_t::ptr_op_t post_t::lookup(const string& name)
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
case 'u':
if (name == "use_direct_amount")
return WRAP_FUNCTOR(get_wrapper<&get_use_direct_amount>);
break;
case 'v':
if (name == "virtual")
return WRAP_FUNCTOR(get_wrapper<&get_virtual>);
@ -333,8 +342,7 @@ void post_t::add_to_value(value_t& value, expr_t& expr)
{
if (xdata_ && xdata_->has_flags(POST_EXT_COMPOUND)) {
add_or_set_value(value, xdata_->value);
}
else if (! xdata_ || ! xdata_->has_flags(POST_EXT_NO_TOTAL)) {
} else {
bind_scope_t bound_scope(*expr.get_context(), *this);
add_or_set_value(value, expr.calc(bound_scope));
}

View file

@ -134,7 +134,7 @@ public:
#define POST_EXT_HANDLED 0x02
#define POST_EXT_TO_DISPLAY 0x04
#define POST_EXT_DISPLAYED 0x08
#define POST_EXT_NO_TOTAL 0x10
#define POST_EXT_DIRECT_AMT 0x10
#define POST_EXT_SORT_CALC 0x20
#define POST_EXT_COMPOUND 0x40
#define POST_EXT_MATCHES 0x80

View file

@ -245,7 +245,7 @@ public:
OPTION(report_t, base);
OPTION_(report_t, basis, DO() { // -B
parent->HANDLER(revalued).off();
parent->HANDLER(revalued).on_only();
parent->HANDLER(amount_).set_expr("rounded(cost)");
});
@ -401,15 +401,17 @@ public:
// Since we are displaying the amounts of revalued postings, they
// will end up being composite totals, and hence a pair of pairs.
parent->HANDLER(display_amount_)
.set_expr("is_seq(get_at(amount_expr, 0)) ?"
" get_at(get_at(amount_expr, 0), 0) :"
" market(get_at(amount_expr, 0), date, exchange) -"
" get_at(amount_expr, 1)");
.set_expr("use_direct_amount ? amount :"
" (is_seq(get_at(amount_expr, 0)) ?"
" get_at(get_at(amount_expr, 0), 0) :"
" market(get_at(amount_expr, 0), date, exchange)"
" - get_at(amount_expr, 1))");
parent->HANDLER(revalued_total_)
.set_expr("(market(get_at(total_expr, 0), date, exchange), "
"get_at(total_expr, 1))");
parent->HANDLER(display_total_)
.set_expr("market(get_at(total_expr, 0), date, exchange)"
.set_expr("use_direct_amount ? total_expr :"
" market(get_at(total_expr, 0), date, exchange)"
" - get_at(total_expr, 1)");
});

110
test/ConfirmTests.py Executable file
View file

@ -0,0 +1,110 @@
#!/usr/bin/python
# This script confirms both that the register report "adds up", and that its
# final balance is the same as what the balance report shows.
import sys
import os
import re
from subprocess import Popen, PIPE
commands = [
"-f '$tests/standard.dat' -O 0ecbb1b15e2cf3e515cc0f8533e5bb0fb2326728",
"-f '$tests/standard.dat' -B c56a21d23a6535184e7152ee138c28974f14280c",
"-f '$tests/standard.dat' -V c56a21d23a6535184e7152ee138c28974f14280c",
"-f '$tests/standard.dat' -G c56a21d23a6535184e7152ee138c28974f14280c",
"-f '$tests/standard.dat' -B c0226fafdf9e6711ac9121cf263e2d50791859cb",
"-f '$tests/standard.dat' -V c0226fafdf9e6711ac9121cf263e2d50791859cb",
"-f '$tests/standard.dat' -G c0226fafdf9e6711ac9121cf263e2d50791859cb"
]
ledger = sys.argv[1]
tests = sys.argv[2]
succeeded = 0
failed = 0
if not os.path.isfile(ledger):
sys.exit(1)
if not os.path.isdir(tests) and not os.path.isfile(tests):
sys.exit(1)
def clean(num):
num = re.sub("(\s+|\$|,)","", num)
m = re.search("([-0-9.]+)", num)
if m:
return float(m.group(1))
else:
return float(num)
def confirm_report(args):
index = 1
last_line = ""
failure = False
running_total = 0.0
p = Popen(re.sub('\$cmd', 'reg', args), shell=True,
stdin=PIPE, stdout=PIPE, stderr=PIPE,
close_fds=True)
for line in p.stdout.readlines():
match = re.match("\\s*([-$,0-9.]+)\\s+([-$,0-9.]+)", line[54:])
if not match:
continue
value = clean(match.group(1))
total = clean(match.group(2))
running_total += value
diff = abs(running_total - total)
if re.search(' -[VGB] ', args) and diff < 0.015:
diff = 0.0
if diff > 0.001:
print "DISCREPANCY: %.3f (%.3f - %.3f) at line %d:" % \
(running_total - total, running_total, total, index)
print line,
running_total = total
failure = True
index += 1
last_line = line
balance_total = 0.0
p = Popen(re.sub('\$cmd', 'bal', args), shell=True,
stdin=PIPE, stdout=PIPE, stderr=PIPE,
close_fds=True)
for line in p.stdout.readlines():
if line[0] != '-':
balance_total = clean(line[:20])
diff = abs(balance_total - running_total)
if re.search(' -[VGB] ', args) and diff < 0.015:
diff = 0.0
if diff > 0.001:
print
print "DISCREPANCY: %.3f (%.3f - %.3f) between register and balance" % \
(balance_total - running_total, balance_total, running_total)
print last_line,
failure = True
return not failure
for cmd in commands:
if confirm_report("%s --args-only --columns=80 %s" %
(ledger, re.sub('\$tests', tests, cmd))):
print ".",
succeeded += 1
else:
print "E",
failed += 1
print
if succeeded > 0:
print "OK (%d) " % succeeded,
if failed > 0:
print "FAILED (%d)" % failed,
print
sys.exit(failed)

View file

@ -125,6 +125,8 @@ def test_regression(test_file):
if success:
succeeded += 1
print ".",
else:
print "E",
if not use_stdin:
os.remove(tempdata[1])

View file

@ -1,3 +0,0 @@
#include <cppunit/extensions/HelperMacros.h>
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("extra");

View file

@ -1,60 +0,0 @@
#!/usr/bin/python
# This script confirms what ledger tells you.
import sys
import os
import re
def clean(num):
num = re.sub("(\s+|\$|,)","", num)
m = re.search("([-0-9.]+)", num)
if m:
return float(m.group(1))
else:
return float(num)
running_total = 0.0
index = 1
last_line = ""
errors = 0
args = sys.argv[1]
for line in os.popen(re.sub('\$cmd', 'reg', args)):
match = re.match("\\s*([-$,0-9.]+)\\s+([-$,0-9.]+)", line[54:])
if not match:
continue
value = clean(match.group(1))
total = clean(match.group(2))
running_total += value
diff = abs(running_total - total)
if re.search(' -[VGB] ', args) and diff < 0.015:
diff = 0.0
if diff > 0.001:
print "DISCREPANCY: %.3f (%.3f - %.3f) at line %d:" % \
(running_total - total, running_total, total, index)
print line,
running_total = total
errors += 1
index += 1
last_line = line
balance_total = 0.0
for line in os.popen(re.sub('\$cmd', 'bal', args)):
if line[0] != '-':
balance_total = clean(line[:20])
diff = abs(balance_total - running_total)
if re.search(' -[VGB] ', args) and diff < 0.015:
diff = 0.0
if diff > 0.001:
print
print "DISCREPANCY: %.3f (%.3f - %.3f) between register and balance" % \
(balance_total - running_total, balance_total, running_total)
print last_line,
errors += 1
sys.exit(errors)

View file

@ -1,22 +0,0 @@
#!/bin/sh
errors=0
for test in \
"-O \$cmd 0ecbb1b15e2cf3e515cc0f8533e5bb0fb2326728" \
"-B \$cmd c56a21d23a6535184e7152ee138c28974f14280c" \
"-V \$cmd c56a21d23a6535184e7152ee138c28974f14280c" \
"-G \$cmd c56a21d23a6535184e7152ee138c28974f14280c" \
"-B \$cmd c0226fafdf9e6711ac9121cf263e2d50791859cb" \
"-V \$cmd c0226fafdf9e6711ac9121cf263e2d50791859cb" \
"-G \$cmd c0226fafdf9e6711ac9121cf263e2d50791859cb"
do
echo testing: $test
python tools/confirm.py "ledger -f tools/standard.dat --args-only --columns=80 $test"
errors=`expr $errors + $?`
done
if [ $errors = 0 ]; then
echo All tests completed successfully.
fi
exit $errors

View file

@ -1,248 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @defgroup the_group Group Title
* @addtogroup the_group
*/
/**
* @file template.h
* @author John Wiegley
*
* @ingroup the_group
*
* @brief Brief description
*
* Full description.
*/
#ifndef _TEMPLATE_H
#define _TEMPLATE_H
namespace template {
/**
* @brief Brief description
*
* Full description.
*/
class template_t : public ordered_field_operators<template_t>
#if 0
public boost::noncopyable
#endif
{
public:
/**
* @name Class statics
*/
/*@{*/
static bool stream_fullstrings;
/*@}*/
/**
* @name Constructors
*/
/*@{*/
/**
* @see other_function
* @warning Watch out!
*/
template_t() {
TRACE_CTOR(template_t, "");
}
/*@}*/
/**
* @name Destructor
*/
/*@{*/
~template_t() {
TRACE_DTOR(template_t);
}
/*@}*/
/**
* @name Assignment and copy
*/
/*@{*/
template_t(const template_t& other) {
TRACE_CTOR(template_t, "copy");
}
template_t& operator=(const template_t& other);
/*@}*/
private:
template_t(const template_t& other);
public:
/**
* @name Comparison
*/
/*@{*/
/**
* Compare two template objects.
* @param other
* @return An integer <0, 0 or >0.
*/
int compare(const template_t& other) const;
template <typename T>
bool operator==(const T& val) const {
return compare(val) == 0;
}
template <typename T>
bool operator<(const T& other) const {
return compare(other) < 0;
}
template <typename T>
bool operator>(const T& other) const {
return compare(other) > 0;
}
/*@}*/
/**
* @name Binary arithmetic
*/
/*@{*/
template_t& operator+=(const template_t& other);
template_t& operator-=(const template_t& other);
template_t& operator*=(const template_t& other);
template_t& operator/=(const template_t& other);
/*@}*/
/**
* @name Unary arithmetic
*/
/*@{*/
template_t operator-() const {
return template_t();
}
/*@}*/
/**
* @name Truth tests
*/
/*@{*/
operator bool() const {
return false;
}
/*@}*/
/**
* @name Conversion
*/
/*@{*/
operator int() const {
return 0;
}
/*@}*/
/**
* @name Parsing
*/
/*@{*/
bool parse(std::istream& in);
bool parse(const string& str) {
std::istringstream stream(str);
bool result = parse(stream, flags);
assert(stream.eof());
return result;
}
/*@}*/
/**
* @name Printing
*/
/*@{*/
void print(std::ostream& out) const;
/*@}*/
/**
* @name Serialization
*/
/*@{*/
void read(std::istream& in);
void read(const char *& data);
void write(std::ostream& out) const;
/*@}*/
/**
* @name XML Serialization
*/
/*@{*/
void read_xml(std::istream& in);
void write_xml(std::ostream& out, const int depth = 0) const;
/*@}*/
/**
* @name Debugging
*/
/*@{*/
void dump(std::ostream& out) const {
print(out);
}
bool valid() const;
/*@}*/
};
} // namespace template
#endif // _TEMPLATE_H