summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Earls <enderw88@gmail.com>2014-02-19 09:46:53 -0700
committerCraig Earls <enderw88@gmail.com>2014-02-19 09:46:53 -0700
commit1ec9f71479a7438f591316fa9004108ffad7594d (patch)
treeb02666e15d611feb857b46bd62d30e45447afc56
parentbe6f3cb2696894b55720cf9063cd508ebeae9f1d (diff)
parent3d9faef448fcbf85bf565ffa9a5830a9fb67fcdd (diff)
downloadfork-ledger-1ec9f71479a7438f591316fa9004108ffad7594d.tar.gz
fork-ledger-1ec9f71479a7438f591316fa9004108ffad7594d.tar.bz2
fork-ledger-1ec9f71479a7438f591316fa9004108ffad7594d.zip
Merge pull request #245 from afh/pull/DocTests
Make more examples from documentation testable
-rw-r--r--doc/ledger3.texi102
-rwxr-xr-xtest/DocTests.py78
2 files changed, 131 insertions, 49 deletions
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
index 0d337b86..54441188 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -56,7 +56,8 @@
@c the documentation itself, in that case the journal example data
@c needs to be specially marked as well using @smallexample @c input:UUID,
@c again with the UUID being the UUID of the corresponding ledger example
-@c command, e.g.:
+@c command. If multiple inputs with the same UUID are found they will be
+@c concatenated together and given as one set of data to the example command.
@c
@c @smallexample @c input:35CB2A3
@c 2014/02/09 The Italian Place
@@ -72,7 +73,19 @@
@c Assets:Cash
@c Expenses:Food:Dining
@c @end smallexample
-@c
+@c
+@c To use different example commands with the same input from the documentation
+@c add with_input:UUID to the example command, where UUID is the UUID of the input,
+@c e.g.:
+@c
+@c @smallexample @c command:94FD2B6,with_input:35CB2A3
+@c $ ledger -f inline.dat bal expenses
+@c @end smallexample
+@c
+@c @smallexample @c output:94FD2B6
+@c $ 36.84 Expenses:Food:Dining
+@c @end smallexample
+@c
@c Additionally DocTests.py will pass --init-file /dev/null to ledger to
@c ignore any default arguments to ledger the user running the tests
@c has configured.
@@ -306,7 +319,7 @@ And just for the sake of example---as a starting point for those who
want to dive in head-first---here are the journal transactions from
above, formatted as the Ledger program wishes to see them:
-@smallexample
+@smallexample @c input:48DDF26
2004/09/29 Pacific Bell
Expenses:Pacific Bell $23.00
Assets:Checking
@@ -315,12 +328,37 @@ above, formatted as the Ledger program wishes to see them:
The account balances and registers in this file, if saved as
@file{ledger.dat}, could be reported using:
-@smallexample
+@smallexample @c command:48DDF26
$ ledger -f ledger.dat balance
+@end smallexample
+
+@smallexample @c output:48DDF26
+ $-23.00 Assets:Checking
+ $23.00 Expenses:Pacific Bell
+--------------------
+ 0
+@end smallexample
+
+Or
+
+@smallexample @c command:8C7295F,with_input:48DDF26
$ ledger -f ledger.dat register checking
+@end smallexample
+
+@smallexample @c output:8C7295F
+04-Sep-29 Pacific Bell Assets:Checking $-23.00 $-23.00
+@end smallexample
+
+And even:
+
+@smallexample @c command:BB32EF2,with_input:48DDF26
$ ledger -f ledger.dat register Bell
@end smallexample
+@smallexample @c output:BB32EF2
+04-Sep-29 Pacific Bell Expenses:Pacific Bell $23.00 $23.00
+@end smallexample
+
An important difference between Ledger and other finance packages is
that Ledger will never alter your input file. You can create and edit
that file in any way you prefer, but Ledger is only for analyzing the
@@ -548,7 +586,7 @@ If you would like to find transaction to only a certain payee use
$ ledger -f drewr3.dat register payee "Organic"
@end smallexample
-@smallexample @c output:C10BC57E
+@smallexample @c output:C6BC57E
10-Dec-20 Organic Co-op Expense:Food:Groceries $ 37.50 $ 37.50
Expense:Food:Groceries $ 37.50 $ 75.00
Expense:Food:Groceries $ 37.50 $ 112.50
@@ -700,7 +738,7 @@ owe. ``Liabilities'' is just a more inclusive name for Debts.
An Asset is typically increased by transferring money from an Income
account, such as when you get paid. Here is a typical transaction:
-@smallexample
+@smallexample @c input:6B43DD4
2004/09/29 My Employer
Assets:Checking $500.00
Income:Salary
@@ -715,7 +753,7 @@ borrow money to buy something, or if you owe someone money. Here is
an example of increasing a MasterCard liability by spending money with
it:
-@smallexample
+@smallexample @c input:6B43DD4
2004/09/30 Restaurant
Expenses:Dining $25.00
Liabilities:MasterCard
@@ -729,10 +767,17 @@ offsets the value of your assets.
The combined total of your Assets and Liabilities is your net worth.
So to see your current net worth, use this command:
-@smallexample
+@smallexample @c command:6B43DD4
$ ledger balance ^assets ^liabilities
@end smallexample
+@smallexample @c output:6B43DD4
+ $500.00 Assets:Checking
+ $-25.00 Liabilities:MasterCard
+--------------------
+ $475.00
+@end smallexample
+
In a similar vein, your Income accounts show up negative, because they
transfer money @emph{from} an account in order to increase your
assets. Your Expenses show up positive because that is where the
@@ -741,10 +786,17 @@ flow. A positive cash flow means you are spending more than you make,
since income is always a negative figure. To see your current cash
flow, use this command:
-@smallexample
+@smallexample @c command:DB128F3,with_input:6B43DD4
$ ledger balance ^income ^expenses
@end smallexample
+@smallexample @c output:DB128F3
+ $25.00 Expenses:Dining
+ $-500.00 Income:Salary
+--------------------
+ $-475.00
+@end smallexample
+
Another common question to ask of your expenses is: How much do I
spend each month on X? Ledger provides a simple way of displaying
monthly totals for any account. Here is an example that summarizes
@@ -1820,7 +1872,7 @@ function on a transaction-wide or per-posting basis.
Lastly, you can specify the valuation function/value for any specific
amount using the @samp{(( ))} commodity annotation.
-@smallexample
+@smallexample @c input:814A366
2012-03-02 KFC
Expenses:Food2 $1 ((2 EUR))
Assets:Cash2
@@ -1856,20 +1908,24 @@ amount using the @samp{(( ))} commodity annotation.
Assets:Cash9
@end smallexample
-@smallexample
-ledger reg -V food
+@smallexample @c command:814A366
+$ ledger reg -V food
+@end smallexample
+
+@smallexample @c output:814A366
12-Mar-02 KFC Expenses:Food2 2 EUR 2 EUR
-12-Mar-03 KFC <Adjustment> -1 EUR 1 EUR
- Expenses:Food3 3 EUR 4 EUR
-12-Mar-04 KFC <Adjustment> -2 EUR 2 EUR
- Expenses:Food4 4 EUR 6 EUR
-12-Mar-05 KFC <Adjustment> -3 EUR 3 EUR
- Expenses:Food5 5 EUR 8 EUR
-12-Mar-06 KFC <Adjustment> -4 EUR 4 EUR
- Expenses:Food6 6 EUR 10 EUR
-12-Mar-07 KFC Expenses:Food7 7 EUR 17 EUR
-12-Mar-08 XACT Expenses:Food8 8 EUR 25 EUR
-12-Mar-09 POST (Expenses:Food9) 9 EUR 34 EUR
+12-Mar-03 KFC Expenses:Food3 3 EUR 5 EUR
+12-Mar-04 KFC Expenses:Food4 4 EUR 9 EUR
+12-Mar-05 KFC Expenses:Food5 $1 $1
+ 9 EUR
+12-Mar-06 KFC Expenses:Food6 $1 $2
+ 9 EUR
+12-Mar-07 KFC Expenses:Food7 1 CAD $2
+ 1 CAD
+ 9 EUR
+12-Mar-08 XACT Expenses:Food8 $1 $3
+ 1 CAD
+ 9 EUR
@end smallexample
@node Keeping it Consistent, Journal Format, Currency and Commodities, Keeping a Journal
diff --git a/test/DocTests.py b/test/DocTests.py
index a50ec03d..cc540aa9 100755
--- a/test/DocTests.py
+++ b/test/DocTests.py
@@ -22,6 +22,7 @@ class DocTests:
self.testin_token = 'command'
self.testout_token = 'output'
self.testdat_token = 'input'
+ self.testwithdat_token = 'with_input'
def read_example(self):
endexample = re.compile(r'^@end\s+smallexample\s*$')
@@ -37,7 +38,7 @@ class DocTests:
return hashlib.sha1(example.rstrip()).hexdigest()[0:7].upper()
def find_examples(self):
- startexample = re.compile(r'^@smallexample\s+@c\s+(%s|%s|%s)(?::([\dA-Fa-f]+))?'
+ startexample = re.compile(r'^@smallexample\s+@c\s+(%s|%s|%s)(?::([\dA-Fa-f]+))?(?:,(.*))?'
% (self.testin_token, self.testout_token, self.testdat_token))
while True:
line = self.file.readline()
@@ -50,6 +51,13 @@ class DocTests:
test_begin_line = self.current_line
test_kind = startmatch.group(1)
test_id = startmatch.group(2)
+ test_options = dict()
+ for pair in re.split(r',\s*', str(startmatch.group(3))):
+ kv = re.split(r':\s*', pair, 2)
+ try:
+ test_options[kv[0]] = kv[1]
+ except IndexError:
+ pass
example = self.read_example()
test_end_pos = self.file.tell()
test_end_line = self.current_line
@@ -68,22 +76,52 @@ class DocTests:
except KeyError:
self.examples[test_id] = dict()
+ try:
+ example = self.examples[test_id][test_kind][test_kind] + example
+ except KeyError:
+ pass
+
self.examples[test_id][test_kind] = {
'bpos': test_begin_pos,
'epos': test_end_pos,
'blin': test_begin_line,
'elin': test_end_line,
+ 'opts': test_options,
test_kind: example,
}
+ def parse_command(self, test_id, example):
+ try:
+ command = example[self.testin_token][self.testin_token]
+ except KeyError:
+ return None
+
+ command = command.rstrip().split()
+ if command[0] == '$': command.remove('$')
+ index = command.index('ledger')
+ command[index] = self.ledger
+ command.insert(index+1, '--init-file')
+ command.insert(index+2, '/dev/null')
+ try:
+ findex = command.index('-f')
+ except ValueError:
+ try:
+ findex = command.index('--file')
+ except ValueError:
+ findex = index+1
+ command.insert(findex, '--file')
+ command.insert(findex+1, test_id + '.dat')
+ return (command, findex+1)
+
def test_examples(self):
failed = set()
for test_id in self.examples:
example = self.examples[test_id]
try:
- command = example[self.testin_token][self.testin_token]
- except KeyError:
- command = None
+ (command, findex) = self.parse_command(test_id, example)
+ except TypeError:
+ failed.add(test_id)
+ continue
try:
output = example[self.testout_token][self.testout_token]
@@ -93,44 +131,32 @@ class DocTests:
try:
input = example[self.testdat_token][self.testdat_token]
except KeyError:
- input = None
+ try:
+ with_input = example[self.testin_token]['opts'][self.testwithdat_token]
+ input = self.examples[with_input][self.testdat_token][self.testdat_token]
+ except KeyError:
+ input = None
if command and output:
- command = command.rstrip().split()
- if command[0] == '$': command.remove('$')
- index = command.index('ledger')
- command[index] = self.ledger
- command.insert(index+1, '--init-file')
- command.insert(index+2, '/dev/null')
- try:
- findex = command.index('-f')
- except ValueError:
- try:
- findex = command.index('--file')
- except ValueError:
- findex = index+1
- command.insert(findex, '--file')
- command.insert(findex+1, test_id + '.dat')
-
+ test_file_created = False
if findex:
scriptpath = os.path.dirname(os.path.realpath(__file__))
test_input_dir = scriptpath + '/../test/input/'
- test_file = command[findex+1]
- test_file_created = False
+ test_file = command[findex]
if not os.path.exists(test_file):
if input:
test_file_created = True
with open(test_file, 'w') as f:
f.write(input)
elif os.path.exists(test_input_dir + test_file):
- command[findex+1] = test_input_dir + test_file
+ command[findex] = test_input_dir + test_file
try:
verify = subprocess.check_output(command)
except:
verify = str()
- if test_file_created:
- os.remove(test_file)
valid = (output == verify)
+ if valid and test_file_created:
+ os.remove(test_file)
if self.verbose > 0:
print test_id, ':', 'Passed' if valid else 'FAILED'
else: