Browse Source

Merge branch 'tor-github/pr/1324'

George Kadianakis 4 years ago
parent
commit
5ec751b38b
42 changed files with 597 additions and 2 deletions
  1. 6 0
      changes/ticket31637
  2. 1 0
      src/test/conf_examples/badnick_1/error
  3. 2 0
      src/test/conf_examples/badnick_1/torrc
  4. 1 0
      src/test/conf_examples/badnick_2/error
  5. 2 0
      src/test/conf_examples/badnick_2/torrc
  6. 1 0
      src/test/conf_examples/contactinfo_notutf8/error
  7. 1 0
      src/test/conf_examples/contactinfo_notutf8/torrc
  8. 2 0
      src/test/conf_examples/example_1/expected
  9. 5 0
      src/test/conf_examples/example_1/torrc
  10. 1 0
      src/test/conf_examples/example_2/error
  11. 1 0
      src/test/conf_examples/example_2/torrc
  12. 1 0
      src/test/conf_examples/example_3/cmdline
  13. 1 0
      src/test/conf_examples/example_3/expected
  14. 0 0
      src/test/conf_examples/example_3/torrc
  15. 3 0
      src/test/conf_examples/include_1/expected
  16. 4 0
      src/test/conf_examples/include_1/included.inc
  17. 2 0
      src/test/conf_examples/include_1/nested.inc
  18. 4 0
      src/test/conf_examples/include_1/torrc
  19. 159 0
      src/test/conf_examples/large_1/expected
  20. 167 0
      src/test/conf_examples/large_1/torrc
  21. 1 0
      src/test/conf_examples/ops_1/cmdline
  22. 2 0
      src/test/conf_examples/ops_1/expected
  23. 3 0
      src/test/conf_examples/ops_1/torrc
  24. 1 0
      src/test/conf_examples/ops_2/cmdline
  25. 0 0
      src/test/conf_examples/ops_2/expected
  26. 3 0
      src/test/conf_examples/ops_2/torrc
  27. 1 0
      src/test/conf_examples/ops_3/cmdline
  28. 3 0
      src/test/conf_examples/ops_3/expected
  29. 3 0
      src/test/conf_examples/ops_3/torrc
  30. 2 0
      src/test/conf_examples/ops_4/expected
  31. 3 0
      src/test/conf_examples/ops_4/torrc
  32. 1 0
      src/test/conf_examples/ops_4/torrc.defaults
  33. 3 0
      src/test/conf_examples/ops_5/expected
  34. 3 0
      src/test/conf_examples/ops_5/torrc
  35. 1 0
      src/test/conf_examples/ops_5/torrc.defaults
  36. 0 0
      src/test/conf_examples/ops_6/expected
  37. 3 0
      src/test/conf_examples/ops_6/torrc
  38. 1 0
      src/test/conf_examples/ops_6/torrc.defaults
  39. 1 0
      src/test/conf_examples/relpath_rad/error
  40. 4 0
      src/test/conf_examples/relpath_rad/torrc
  41. 4 2
      src/test/include.am
  42. 190 0
      src/test/test_parseconf.sh

+ 6 - 0
changes/ticket31637

@@ -0,0 +1,6 @@
+  o Minor features (testing):
+    - Add a script to invoke "tor --dump-config" and "tor --verify-config"
+      with various configuration options, and see whether tor's resulting
+      configuration or error messages are what we expect. Use it for
+      integration testing of our +Option and /Option flags.
+      Closes ticket 31637.

+ 1 - 0
src/test/conf_examples/badnick_1/error

@@ -0,0 +1 @@
+nicknames must be between 1 and 19 characters inclusive

+ 2 - 0
src/test/conf_examples/badnick_1/torrc

@@ -0,0 +1,2 @@
+# This nickname is too long; we won't accept it.
+Nickname TooManyCharactersInThisNickname

+ 1 - 0
src/test/conf_examples/badnick_2/error

@@ -0,0 +1 @@
+must contain only the characters \[a-zA-Z0-9\]

+ 2 - 0
src/test/conf_examples/badnick_2/torrc

@@ -0,0 +1,2 @@
+# this nickname has spaces in it and won't work.
+Nickname has a space

+ 1 - 0
src/test/conf_examples/contactinfo_notutf8/error

@@ -0,0 +1 @@
+ContactInfo config option must be UTF-8

+ 1 - 0
src/test/conf_examples/contactinfo_notutf8/torrc

@@ -0,0 +1 @@
+ContactInfo ÄëÄëÄë@example.com

+ 2 - 0
src/test/conf_examples/example_1/expected

@@ -0,0 +1,2 @@
+ContactInfo tor_tellini@example.com
+SocksPort 80

+ 5 - 0
src/test/conf_examples/example_1/torrc

@@ -0,0 +1,5 @@
+
+# Here is a simple example torrc.
+  SocksPort  80
+
+ContactInfo "tor_tellini@example.com"

+ 1 - 0
src/test/conf_examples/example_2/error

@@ -0,0 +1 @@
+Unknown option 'JumpingJellyjars'

+ 1 - 0
src/test/conf_examples/example_2/torrc

@@ -0,0 +1 @@
+JumpingJellyjars 1

+ 1 - 0
src/test/conf_examples/example_3/cmdline

@@ -0,0 +1 @@
+--socksport 99

+ 1 - 0
src/test/conf_examples/example_3/expected

@@ -0,0 +1 @@
+SocksPort 99

+ 0 - 0
src/test/conf_examples/example_3/torrc


+ 3 - 0
src/test/conf_examples/include_1/expected

@@ -0,0 +1,3 @@
+ContactInfo includefile@example.com
+Nickname nested
+ORPort 8008

+ 4 - 0
src/test/conf_examples/include_1/included.inc

@@ -0,0 +1,4 @@
+
+ContactInfo includefile@example.com
+
+%include "nested.inc"

+ 2 - 0
src/test/conf_examples/include_1/nested.inc

@@ -0,0 +1,2 @@
+
+Nickname nested

+ 4 - 0
src/test/conf_examples/include_1/torrc

@@ -0,0 +1,4 @@
+
+%include "included.inc"
+
+ORPort 8008

+ 159 - 0
src/test/conf_examples/large_1/expected

@@ -0,0 +1,159 @@
+AccountingMax 10737418240
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AndroidIdentityTag droidy
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2147483647
+BandwidthRate 1610612736
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientAutoIPv6ORPort 1
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConsensusParams wombat=7
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirPortFrontPage /dirport/frontpage
+DirPort 99
+DirReqStatistics 0
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 1260
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 300
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPortCookieAuthFile /foobar
+ExtORPort 99
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 691200
+HeartbeatPeriod 2700
+IPv6Exit 1
+KeepalivePeriod 540
+KeyDirectory /keyz
+KISTSchedRunInterval 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 60000
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 3600
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 2629728
+MaxMemInQueues 314572800
+MaxOnionQueueDelay 60000
+MaxUnparseableDescSizeToLog 1048576
+MiddleNodes grommit,truffle,parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 7200
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+OptimisticData 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PerConnBWBurst 10485760
+PerConnBWRate 102400
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 600
+RephistTrackTime 600
+SafeLogging 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10
+SigningKeyLifetime 4838400
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 600
+SSLKeyLifetime 86400
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1000
+TrackHostExits www.example.com
+TrackHostExitsExpire 3600
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001

+ 167 - 0
src/test/conf_examples/large_1/torrc

@@ -0,0 +1,167 @@
+AccountingMax 10 GB
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AndroidIdentityTag droidy
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2 GB
+BandwidthRate 1.5 GB
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitPadding 1
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientAutoIPv6ORPort 1
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConsensusParams wombat=7
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirReqStatistics 0
+DirPort 99
+DirPortFrontPage /dirport/frontpage
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 21 minutes
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 5 minutes
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPort 99
+ExtORPortCookieAuthFile /foobar
+ExtraInfoStatistics 1
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchHidServDescriptors 1
+FetchServerDescriptors 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 8 days
+HeartbeatPeriod 45 minutes
+IPv6Exit 1
+KeepalivePeriod 9 minutes
+KeyDirectory /keyz
+KISTSchedRunInterval 1 msec
+LearnCircuitBuildTimeout 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 1 minute
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 1 hour
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 1 month
+MaxMemInQueues 300 MB
+MaxOnionQueueDelay 60 seconds
+MaxUnparseableDescSizeToLog 1 MB
+MiddleNodes grommit, truffle, parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 2 hours
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+OptimisticData 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PaddingStatistics 1
+PerConnBWBurst 10 MB
+PerConnBWRate 100 kb
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 10 minutes
+RephistTrackTime 10 minutes
+SafeLogging 0
+SafeSocks 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10 seconds
+SigningKeyLifetime 8 weeks
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 10 minutes
+SSLKeyLifetime 1 day
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1 second
+TrackHostExits www.example.com
+TrackHostExitsExpire 1 hour
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseEntryGuards 1
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001

+ 1 - 0
src/test/conf_examples/ops_1/cmdline

@@ -0,0 +1 @@
+ORPort 1000

+ 2 - 0
src/test/conf_examples/ops_1/expected

@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1000

+ 3 - 0
src/test/conf_examples/ops_1/torrc

@@ -0,0 +1,3 @@
+# We'll replace this option on the command line.
+
+ORPort 9999

+ 1 - 0
src/test/conf_examples/ops_2/cmdline

@@ -0,0 +1 @@
+/ORPort

+ 0 - 0
src/test/conf_examples/ops_2/expected


+ 3 - 0
src/test/conf_examples/ops_2/torrc

@@ -0,0 +1,3 @@
+# We'll remove this option on the command line, and not replace it.
+
+ORPort 9999

+ 1 - 0
src/test/conf_examples/ops_3/cmdline

@@ -0,0 +1 @@
++ORPort 1000

+ 3 - 0
src/test/conf_examples/ops_3/expected

@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 9999
+ORPort 1000

+ 3 - 0
src/test/conf_examples/ops_3/torrc

@@ -0,0 +1,3 @@
+# We will extend this option on the command line
+
+ORPort 9999

+ 2 - 0
src/test/conf_examples/ops_4/expected

@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 9099

+ 3 - 0
src/test/conf_examples/ops_4/torrc

@@ -0,0 +1,3 @@
+# This value is unadorned, so replaces the one from defaults.torrc.
+
+ORPort 9099

+ 1 - 0
src/test/conf_examples/ops_4/torrc.defaults

@@ -0,0 +1 @@
+ORPort 9000

+ 3 - 0
src/test/conf_examples/ops_5/expected

@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 9000
+ORPort 9099

+ 3 - 0
src/test/conf_examples/ops_5/torrc

@@ -0,0 +1,3 @@
+# This value has a plus, and so extends the one from defaults.torrc.
+
++ORPort 9099

+ 1 - 0
src/test/conf_examples/ops_5/torrc.defaults

@@ -0,0 +1 @@
+ORPort 9000

+ 0 - 0
src/test/conf_examples/ops_6/expected


+ 3 - 0
src/test/conf_examples/ops_6/torrc

@@ -0,0 +1,3 @@
+# This value has a slash, and so clears the one from defaults.torrc.
+
+/ORPort

+ 1 - 0
src/test/conf_examples/ops_6/torrc.defaults

@@ -0,0 +1 @@
+ORPort 9000

+ 1 - 0
src/test/conf_examples/relpath_rad/error

@@ -0,0 +1 @@
+RunAsDaemon is not compatible with relative paths.

+ 4 - 0
src/test/conf_examples/relpath_rad/torrc

@@ -0,0 +1,4 @@
+
+# Relative-path data directories are incompatible with RunAsDaemon
+DataDirectory ./datadir
+RunAsDaemon 1

+ 4 - 2
src/test/include.am

@@ -24,7 +24,8 @@ TESTSCRIPTS = \
 	src/test/test_workqueue_pipe2.sh \
 	src/test/test_workqueue_socketpair.sh \
 	src/test/test_switch_id.sh \
-	src/test/test_cmdline.sh
+	src/test/test_cmdline.sh \
+	src/test/test_parseconf.sh
 
 if USE_RUST
 TESTSCRIPTS += \
@@ -414,7 +415,8 @@ EXTRA_DIST += \
 	src/test/test_workqueue_pipe.sh \
 	src/test/test_workqueue_pipe2.sh \
 	src/test/test_workqueue_socketpair.sh \
-	src/test/test_cmdline.sh
+	src/test/test_cmdline.sh \
+	src/test/test_parseconf.sh
 
 test-rust:
 	$(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh"

+ 190 - 0
src/test/test_parseconf.sh

@@ -0,0 +1,190 @@
+#!/bin/sh
+# Copyright 2019, The Tor Project, Inc.
+# See LICENSE for licensing information
+
+# Integration test script for verifying that Tor configurations are parsed as
+# we expect.
+#
+# Valid configurations are tested with --dump-config, which parses and
+# validates the configuration before writing it out.  We then make sure that
+# the result is what we expect, before parsing and dumping it again to make
+# sure that there is no change.
+#
+# Invalid configurations are tested with --verify-config, which parses
+# and validates the configuration. We capture its output and make sure that
+# it contains the error message we expect.
+
+# This script looks for its test cases as individual directories in
+# src/test/conf_examples/.  Each test may have these files:
+#
+# torrc -- Usually needed. This file is passed to Tor on the command line
+#      with the "-f" flag. (If you omit it, you'll test Tor's behavior when
+#      it receives a nonexistent configuration file.)
+#
+# torrc.defaults -- Optional. If present, it is passed to Tor on the command
+#      line with the --defaults-torrc option. If this file is absent, an empty
+#      file is passed instead to prevent Tor from reading the system defaults.
+#
+# cmdline -- Optional. If present, it contains command-line arguments that
+#      will be passed to Tor.
+#
+# expected -- If this file is present, then it should be the expected result
+#      of "--dump-config short" for this test case.  Exactly one of
+#      "expected" or "error" must be present, or the test will fail.
+#
+# error -- If this file is present, then it contains a regex that must be
+#      matched by some line in the output of "--verify-config", which must
+#      fail. Exactly one of "expected" or "error" must be present, or the
+#      test will fail.
+
+umask 077
+set -e
+die() { echo "$1" >&2 ; exit 5; }
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+    f=$@
+    if [ -d "$f" ]; then
+        dir="$f"
+        base=""
+    else
+        dir="$(dirname "$f")"
+        base="/$(basename "$f")"
+    fi
+    dir="$(cd "$dir" && pwd)"
+    echo "$dir$base"
+}
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+  TOR_BINARY="${1}"
+  shift
+else
+  TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+# make a safe space for temporary files
+DATA_DIR=$(mktemp -d -t tor_parseconf_tests.XXXXXX)
+trap 'rm -rf "$DATA_DIR"' 0
+touch "${DATA_DIR}/EMPTY" || die "Couldn't create empty file."
+
+# This is where we look for examples
+EXAMPLEDIR="$(dirname "$0")"/conf_examples
+
+case "$(uname -s)" in
+    CYGWIN*) WINDOWS=1;;
+    MINGW*) WINDOWS=1;;
+    MSYS*) WINDOWS=1;;
+    *) WINDOWS=0;;
+esac
+
+if test "$WINDOWS" = 1; then
+    FILTER="dos2unix"
+else
+    FILTER="cat"
+fi
+
+for dir in "${EXAMPLEDIR}"/*; do
+    if ! test -d "${dir}"; then
+       # Only count directories.
+       continue
+    fi
+
+    testname="$(basename "${dir}")"
+    # We use printf since "echo -n" is not standard
+    printf "%s: " "$testname"
+
+    PREV_DIR="$(pwd)"
+    cd "${dir}"
+
+    if test -f "./torrc.defaults"; then
+        DEFAULTS="./torrc.defaults"
+    else
+        DEFAULTS="${DATA_DIR}/EMPTY"
+    fi
+
+    if test -f "./cmdline"; then
+        CMDLINE="$(cat ./cmdline)"
+    else
+        CMDLINE=""
+    fi
+
+    if test -f "./expected"; then
+        if test -f "./error"; then
+            echo "FAIL: Found both ${dir}/expected and ${dir}/error."
+            echo "(Only one of these files should exist.)"
+            exit 1
+        fi
+
+        # This case should succeed: run dump-config and see if it does.
+
+        "${TOR_BINARY}" -f "./torrc" \
+                        --defaults-torrc "${DEFAULTS}" \
+                        --dump-config short \
+                        ${CMDLINE} \
+                        | "${FILTER}" > "${DATA_DIR}/output.${testname}" \
+                        || die "Failure: Tor exited."
+
+        if cmp "./expected" "${DATA_DIR}/output.${testname}">/dev/null ; then
+            # Check round-trip.
+            "${TOR_BINARY}" -f "${DATA_DIR}/output.${testname}" \
+                            --defaults-torrc "${DATA_DIR}/empty" \
+                            --dump-config short \
+                            | "${FILTER}" \
+                            > "${DATA_DIR}/output_2.${testname}" \
+                        || die "Failure: Tor exited on round-trip."
+
+            if ! cmp "${DATA_DIR}/output.${testname}" \
+                 "${DATA_DIR}/output_2.${testname}"; then
+                echo "Failure: did not match on round-trip."
+                exit 1
+            fi
+
+            echo "OK"
+        else
+            echo "FAIL"
+            if test "$(wc -c < "${DATA_DIR}/output.${testname}")" = 0; then
+                # There was no output -- probably we failed.
+                "${TOR_BINARY}" -f "./torrc" \
+                                --defaults-torrc "${DEFAULTS}" \
+                                --verify-config \
+                                ${CMDLINE} || true
+            fi
+            diff -u "./expected" "${DATA_DIR}/output.${testname}"
+            exit 1
+        fi
+
+   elif test -f "./error"; then
+        # This case should fail: run verify-config and see if it does.
+
+        "${TOR_BINARY}" --verify-config \
+                        -f ./torrc \
+                        --defaults-torrc "${DEFAULTS}" \
+                        ${CMDLINE} \
+                        > "${DATA_DIR}/output.${testname}" \
+                        && die "Failure: Tor did not report an error."
+
+        expect_err="$(cat ./error)"
+        if grep "${expect_err}" "${DATA_DIR}/output.${testname}" >/dev/null; then
+            echo "OK"
+        else
+            echo "FAIL"
+            echo "Expected error: ${expect_err}"
+            echo "Tor said:"
+            cat "${DATA_DIR}/output.${testname}"
+            exit 1
+        fi
+
+    else
+        # This case is not actually configured with a success or a failure.
+        # call that an error.
+
+        echo "FAIL: Did not find ${dir}/expected or ${dir}/error."
+        exit 1
+    fi
+
+    cd "${PREV_DIR}"
+
+done