pax_global_header00006660000000000000000000000064141067454340014522gustar00rootroot0000000000000052 comment=032d90d1300a4c1d61687b61d047745b91fb99d0 mod_tile-0.6.1/000077500000000000000000000000001410674543400133225ustar00rootroot00000000000000mod_tile-0.6.1/.github/000077500000000000000000000000001410674543400146625ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/000077500000000000000000000000001410674543400163225ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/apt/000077500000000000000000000000001410674543400171065ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/apt/install/000077500000000000000000000000001410674543400205545ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/apt/install/action.yml000066400000000000000000000003471410674543400225600ustar00rootroot00000000000000--- inputs: packages: description: List of package(s) to install required: true runs: using: composite steps: - name: Install package(s) run: sudo apt --yes install ${{ inputs.packages }} shell: bash mod_tile-0.6.1/.github/actions/apt/provision/000077500000000000000000000000001410674543400211365ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/apt/provision/action.yml000066400000000000000000000003731410674543400231410ustar00rootroot00000000000000--- inputs: packages: description: List of package(s) to install required: true runs: using: composite steps: - name: Install package(s) uses: ./.github/actions/apt/install with: packages: ${{ inputs.packages }} mod_tile-0.6.1/.github/actions/build-archive/000077500000000000000000000000001410674543400210405ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/build-archive/create/000077500000000000000000000000001410674543400223035ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/build-archive/create/action.yml000066400000000000000000000004461410674543400243070ustar00rootroot00000000000000--- runs: using: composite steps: - name: Create build archive run: | tar --verbose --create --gzip \ --exclude=.git --exclude=.gitgnore \ --file=/tmp/workspace.tar.gz \ * shell: bash working-directory: ${{ github.workspace }}/.. mod_tile-0.6.1/.github/actions/build-archive/extract/000077500000000000000000000000001410674543400225125ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/build-archive/extract/action.yml000066400000000000000000000003531410674543400245130ustar00rootroot00000000000000--- runs: using: composite steps: - name: Extract build archive run: | tar --verbose --extract --gzip \ --file=/tmp/workspace.tar.gz shell: bash working-directory: ${{ github.workspace }}/.. mod_tile-0.6.1/.github/actions/yum/000077500000000000000000000000001410674543400171345ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/yum/groups-install/000077500000000000000000000000001410674543400221175ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/yum/groups-install/action.yml000066400000000000000000000003471410674543400241230ustar00rootroot00000000000000--- inputs: groups: description: List of group(s) to install required: true runs: using: composite steps: - name: Install group(s) run: yum --assumeyes groups install ${{ inputs.groups }} shell: bash mod_tile-0.6.1/.github/actions/yum/install/000077500000000000000000000000001410674543400206025ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/yum/install/action.yml000066400000000000000000000003501410674543400226000ustar00rootroot00000000000000--- inputs: packages: description: List of package(s) to install required: true runs: using: composite steps: - name: Install package(s) run: yum --assumeyes install ${{ inputs.packages }} shell: bash mod_tile-0.6.1/.github/actions/yum/provision/000077500000000000000000000000001410674543400211645ustar00rootroot00000000000000mod_tile-0.6.1/.github/actions/yum/provision/action.yml000066400000000000000000000007571410674543400231750ustar00rootroot00000000000000--- inputs: groups: description: List of group(s) to install required: false default: >- "Development Tools" packages: description: List of package(s) to install required: true runs: using: composite steps: - name: Install group(s) uses: ./.github/actions/yum/groups-install with: groups: ${{ inputs.groups }} - name: Install package(s) uses: ./.github/actions/yum/install with: packages: ${{ inputs.packages }} mod_tile-0.6.1/.github/workflows/000077500000000000000000000000001410674543400167175ustar00rootroot00000000000000mod_tile-0.6.1/.github/workflows/build-and-test-centos-7.yml000066400000000000000000000111371410674543400237160ustar00rootroot00000000000000--- name: Build & Test (CentOS 7) on: push: branches: - master - distros/centos-7 env: build-dependencies: >- boost169-devel cairo-devel freetype-devel gdal-devel glib2-devel harfbuzz-devel httpd-devel iniparser-devel libcurl-devel libicu-devel libjpeg-turbo-devel libmemcached-devel libpng-devel librados2-devel libtiff-devel libwebp-devel libxml2-devel postgresql-devel proj-devel sqlite-devel zlib-devel mapnik-version: 3.0.24 jobs: build-and-test: name: Build & Test runs-on: ubuntu-latest container: image: centos:7 env: LD_LIBRARY_PATH: /usr/local/lib steps: - name: Checkout code uses: actions/checkout@v2 - name: Install `EPEL` yum repository uses: ./.github/actions/yum/install with: packages: epel-release - name: Provision environment uses: ./.github/actions/yum/provision with: packages: ${{ env.build-dependencies }} - name: Cache "Download `Mapnik`" & "Build & Install `Mapnik`" id: cache-mapnik uses: actions/cache@v2 with: path: /usr/local/src/mapnik-${{ env.mapnik-version }} key: centos-7-mapnik-${{ env.mapnik-version }} - name: Download `Mapnik` if: steps.cache-mapnik.outputs.cache-hit != 'true' run: | mkdir /usr/local/src/mapnik-${{ env.mapnik-version }} cd /usr/local/src/mapnik-${{ env.mapnik-version }} curl --silent --location \ https://github.com/mapnik/mapnik/releases/download/v${{ env.mapnik-version }}/mapnik-v${{ env.mapnik-version }}.tar.bz2 \ | tar --verbose --extract --bzip2 --strip-components=1 --file=- - name: Build & Install `Mapnik` run: | # Export `GDAL_DATA` & `PROJ_LIB` variables and create directories (if needed) export GDAL_DATA=$(gdal-config --datadir) export PROJ_LIB=/usr/share/proj mkdir -p ${GDAL_DATA} ${PROJ_LIB} cd /usr/local/src/mapnik-${{ env.mapnik-version }} ./configure BOOST_INCLUDES=/usr/include/boost169 BOOST_LIBS=/usr/lib64/boost169 JOBS=$(nproc) make make install - name: Link `iniparser.h` to `iniparser/iniparser.h` run: | mkdir /usr/include/iniparser ln -s /usr/include/iniparser.h /usr/include/iniparser/iniparser.h - name: Run `./autogen.sh` run: ./autogen.sh - name: Run `./configure` run: ./configure - name: Run `make` run: make - name: Run `make test` run: make test - name: Configure Apache HTTP Server run: | mkdir --parents /usr/share/javascript/leaflet curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" \ > /usr/share/javascript/leaflet/leaflet.min.js curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" \ > /usr/share/javascript/leaflet/leaflet.css mkdir --parents /run/renderd /var/cache/renderd/tiles ln --symbolic \ "${PWD}/utils/example-map" \ /var/www/ ln --symbolic \ /usr/share/javascript/leaflet \ /var/www/example-map/leaflet ln --symbolic \ "${PWD}/etc/renderd/renderd.conf.examples" \ /etc/renderd.conf ln --symbolic \ "${PWD}/etc/apache2/renderd.conf" \ /etc/httpd/conf.d/renderd.conf ln --symbolic \ "${PWD}/etc/apache2/renderd-example-map.conf" \ /etc/httpd/conf.d/renderd-example-map.conf echo "LoadModule tile_module /usr/lib64/httpd/modules/mod_tile.so" \ | tee --append /etc/httpd/conf.modules.d/11-mod_tile.conf sed --in-place \ "s#/usr/lib/mapnik/3.0/input#/usr/local/lib/mapnik/input#g" \ /etc/renderd.conf sed --in-place \ "s#/usr/share/fonts/truetype#/usr/share/fonts#g" \ /etc/renderd.conf rm --force /etc/httpd/conf.d/welcome.conf - name: Run `make install` run: make install - name: Run `make install-mod_tile` run: make install-mod_tile - name: Start `renderd` run: renderd - name: Start Apache HTTP Server run: httpd - name: Test Apache HTTP Server `mod_tile` module run: | curl --silent http://localhost/renderd-example/tiles/9/297/191.png \ | sha224sum - \ | grep 9cd82e5af9d9002a1c75126ebdb7bf054ec0b7ed0db228dfb0a09bae mod_tile-0.6.1/.github/workflows/build-and-test-fedora-34.yml000066400000000000000000000057661410674543400237560ustar00rootroot00000000000000--- name: Build & Test (Fedora 34) on: pull_request: push: branches: - master - develop - distros/fedora-34 env: build-group-dependencies: >- "C Development Tools and Libraries" "Development Libraries" "Development Tools" build-dependencies: >- cairo-devel glib2-devel httpd-devel iniparser-devel libcurl-devel libmemcached-devel librados-devel mapnik-devel jobs: build-and-test: name: Build & Test runs-on: ubuntu-latest container: image: fedora:34 steps: - name: Checkout code uses: actions/checkout@v2 - name: Provision environment uses: ./.github/actions/yum/provision with: groups: ${{ env.build-group-dependencies }} packages: ${{ env.build-dependencies }} httpd - name: Run `./autogen.sh` run: ./autogen.sh - name: Run `./configure` run: ./configure - name: Run `make` run: make - name: Run `make test` run: make test - name: Configure Apache HTTP Server run: | mkdir --parents /usr/share/javascript/leaflet curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" \ > /usr/share/javascript/leaflet/leaflet.min.js curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" \ > /usr/share/javascript/leaflet/leaflet.css mkdir --parents /run/renderd /var/cache/renderd/tiles ln --symbolic \ "${PWD}/utils/example-map" \ /var/www/ ln --symbolic \ /usr/share/javascript/leaflet \ /var/www/example-map/leaflet ln --symbolic \ "${PWD}/etc/renderd/renderd.conf.examples" \ /etc/renderd.conf ln --symbolic \ "${PWD}/etc/apache2/renderd.conf" \ /etc/httpd/conf.d/renderd.conf ln --symbolic \ "${PWD}/etc/apache2/renderd-example-map.conf" \ /etc/httpd/conf.d/renderd-example-map.conf echo "LoadModule tile_module /usr/lib64/httpd/modules/mod_tile.so" \ | tee --append /etc/httpd/conf.modules.d/11-mod_tile.conf sed --in-place \ "s#/usr/lib/mapnik/3.0/input#/usr/lib64/mapnik/input#g" \ /etc/renderd.conf sed --in-place \ "s#/usr/share/fonts/truetype#/usr/share/fonts#g" \ /etc/renderd.conf rm --force /etc/httpd/conf.d/welcome.conf - name: Run `make install` run: make install - name: Run `make install-mod_tile` run: make install-mod_tile - name: Start `renderd` run: renderd - name: Start Apache HTTP Server run: httpd - name: Test Apache HTTP Server `mod_tile` module run: | curl --silent http://localhost/renderd-example/tiles/9/297/191.png \ | sha224sum - \ | grep 9cd82e5af9d9002a1c75126ebdb7bf054ec0b7ed0db228dfb0a09bae mod_tile-0.6.1/.github/workflows/build-and-test-ubuntu-20-04.yml000066400000000000000000000044441410674543400242440ustar00rootroot00000000000000--- name: Build & Test (Ubuntu 20.04) on: pull_request: push: branches: - master - develop - distros/ubuntu-20-04 env: build-dependencies: >- apache2-dev libcairo2-dev libcurl4-gnutls-dev libglib2.0-dev libiniparser-dev libmapnik-dev libmemcached-dev librados-dev jobs: build-and-test: name: Build & Test runs-on: ubuntu-20.04 steps: - name: Checkout code uses: actions/checkout@v2 - name: Provision environment uses: ./.github/actions/apt/provision with: packages: >- ${{ env.build-dependencies }} apache2 libjs-leaflet - name: Run `./autogen.sh` run: ./autogen.sh - name: Run `./configure` run: ./configure - name: Run `make` run: make - name: Run `make test` run: make test - name: Configure Apache HTTP Server run: | sudo mkdir --parents /run/renderd /var/cache/renderd/tiles sudo ln --symbolic \ "${PWD}/utils/example-map" \ /var/www/ sudo ln --symbolic \ /usr/share/javascript/leaflet \ /var/www/example-map/leaflet sudo ln --symbolic \ "${PWD}/etc/renderd/renderd.conf.examples" \ /etc/renderd.conf sudo ln --symbolic \ "${PWD}/etc/apache2/renderd.conf" \ /etc/apache2/conf-enabled/renderd.conf sudo ln --symbolic \ "${PWD}/etc/apache2/renderd-example-map.conf" \ /etc/apache2/conf-enabled/renderd-example-map.conf echo "LoadModule tile_module /usr/lib/apache2/modules/mod_tile.so" \ | sudo tee --append /etc/apache2/mods-enabled/mod_tile.load - name: Run `sudo make install` run: sudo make install - name: Run `make install-mod_tile` run: sudo make install-mod_tile - name: Start `renderd` run: sudo renderd - name: Enable & start Apache HTTP Server run: sudo systemctl --now enable apache2 - name: Test Apache HTTP Server `mod_tile` module run: | curl --silent http://localhost/renderd-example/tiles/9/297/191.png \ | sha224sum - \ | grep 9cd82e5af9d9002a1c75126ebdb7bf054ec0b7ed0db228dfb0a09bae mod_tile-0.6.1/.github/workflows/flawfinder-analysis.yml000066400000000000000000000014741410674543400234120ustar00rootroot00000000000000name: flawfinder on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '44 0 * * 4' jobs: flawfinder: name: Flawfinder runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write steps: - name: Checkout code uses: actions/checkout@v2 - name: flawfinder_scan uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c with: arguments: '--sarif ./' output: 'flawfinder_results.sarif' - name: Upload analysis results to GitHub Security tab uses: github/codeql-action/upload-sarif@v1 with: sarif_file: ${{github.workspace}}/flawfinder_results.sarif mod_tile-0.6.1/.github/workflows/lint.yml000066400000000000000000000021611410674543400204100ustar00rootroot00000000000000--- name: Lint on: pull_request: push: branches: - master - develop jobs: astyle: name: Lint with `astyle` runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Provision environment uses: ./.github/actions/apt/provision with: packages: astyle - name: Run `astyle` run: | astyle \ --options=none --lineend=linux --style=1tbs --indent=force-tab=8 \ --break-blocks --indent-switches --pad-oper --pad-header \ --unpad-paren --suffix=none \ includes/* src/* - name: Check if any modifications were made by `astyle` run: | if [[ -n $(git diff) ]]; then echo "You must run 'astyle \ --options=none --lineend=linux --style=1tbs --indent=force-tab=8 \ --break-blocks --indent-switches --pad-oper --pad-header \ --unpad-paren --suffix=none \ includes/* src/*' before submitting a pull request" echo "" git diff exit -1 fi mod_tile-0.6.1/.gitignore000066400000000000000000000007751410674543400153230ustar00rootroot00000000000000.deps/ .dirstamp .libs/ *.la *.lo *.o *.slo aclocal.m4 autom4te.cache/ compile config.guess config.guess~ config.h config.h.in config.h.in~ config.log config.status config.sub config.sub~ configure configure~ depcomp gen_tile_test install-sh libtool ltmain.sh m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 Makefile* missing render_expired render_list render_old render_speedtest renderd renderd.sock renderd.stats stamp-h1 stderr.out # Do not ignore !Makefile.am !etc/renderd mod_tile-0.6.1/AUTHORS000066400000000000000000000025041410674543400143730ustar00rootroot00000000000000Ævar Arnfjörð Bjarmason Anton Belichkov Andreas Hubel Bas Couwenberg Ben Hosmer Ben Kochie Brian Quinion Christoph Brill Dane Springmeyer David Hummel <6109326+hummeltech@users.noreply.github.com> Dirk Stöcker Eric Stadtherr Felix Delattre Frederik Ramm Ircama JaimeLynSchatz Jocelyn Jaubert Jochen Topf Jon Burgess Kai Krueger Lennard voor den Dag Manfred Stock Matt Amos Michael Fazio Moritz Seemann Paul Norman Peter Körner Rainer Jung Ramunas Robert Buchholz rusvdw Sean Reifschneider Stephan Knauss Stephan Plepelits Tom Hughes Xin Yu Zverik mod_tile-0.6.1/COPYING000066400000000000000000000432541410674543400143650ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. mod_tile-0.6.1/Makefile.am000066400000000000000000000072351410674543400153650ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = $(PTHREAD_CFLAGS) $(GLIB_CFLAGS) STORE_SOURCES = \ src/store.c \ src/store_file.c \ src/store_file_utils.c \ src/store_memcached.c \ src/store_rados.c \ src/store_ro_http_proxy.c \ src/store_ro_composite.c \ src/store_null.c \ src/g_logger.c STORE_LDFLAGS = $(LIBMEMCACHED_LDFLAGS) $(LIBRADOS_LDFLAGS) $(LIBCURL) $(GLIB_LIBS) STORE_CPPFLAGS = bin_PROGRAMS = \ renderd \ render_expired \ render_list \ render_speedtest \ render_old noinst_PROGRAMS = gen_tile_test man_MANS = \ docs/man/renderd.1 \ docs/man/render_expired.1 \ docs/man/render_list.1 \ docs/man/render_old.1 \ docs/man/render_speedtest.1 renderddir = $(sysconfdir) renderd_SOURCES = \ src/daemon.c \ src/daemon_compat.c \ src/gen_tile.cpp \ src/sys_utils.c \ src/request_queue.c \ src/cache_expire.c \ src/metatile.cpp \ src/parameterize_style.cpp \ src/protocol_helper.c \ $(STORE_SOURCES) renderd_CXXFLAGS = $(MAPNIK_CFLAGS) renderd_LDADD = $(PTHREAD_CFLAGS) $(MAPNIK_LDFLAGS) $(STORE_LDFLAGS) -liniparser renderd_DATA = etc/renderd/renderd.conf render_speedtest_SOURCES = \ src/speedtest.cpp \ src/protocol_helper.c \ src/render_submit_queue.c \ src/sys_utils.c \ src/g_logger.c render_speedtest_LDADD = $(PTHREAD_CFLAGS) $(GLIB_LIBS) render_list_SOURCES = \ src/render_list.c \ src/sys_utils.c \ src/protocol_helper.c \ src/render_submit_queue.c \ $(STORE_SOURCES) render_list_LDADD = $(PTHREAD_CFLAGS) $(STORE_LDFLAGS) render_expired_SOURCES = \ src/render_expired.c \ src/protocol_helper.c \ src/render_submit_queue.c \ src/sys_utils.c \ $(STORE_SOURCES) render_expired_LDADD = $(PTHREAD_CFLAGS) $(STORE_LDFLAGS) render_old_SOURCES = \ src/store_file_utils.c \ src/render_old.c \ src/sys_utils.c \ src/protocol_helper.c \ src/render_submit_queue.c \ src/g_logger.c render_old_LDADD = $(PTHREAD_CFLAGS) $(GLIB_LIBS) #convert_meta_SOURCES = src/dir_utils.c src/store.c src/convert_meta.c gen_tile_test_SOURCES = \ src/gen_tile_test.cpp \ src/metatile.cpp \ src/request_queue.c \ src/protocol_helper.c \ src/daemon.c \ src/daemon_compat.c \ src/gen_tile.cpp \ src/sys_utils.c \ src/cache_expire.c \ src/parameterize_style.cpp \ $(STORE_SOURCES) gen_tile_test_CFLAGS = -DMAIN_ALREADY_DEFINED $(PTHREAD_CFLAGS) $(GLIB_CFLAGS) gen_tile_test_CXXFLAGS = $(MAPNIK_CFLAGS) gen_tile_test_LDADD = $(PTHREAD_CFLAGS) $(MAPNIK_LDFLAGS) $(STORE_LDFLAGS) -liniparser CLEANFILES=*.slo mod_tile.la stderr.out src/*.slo src/*.lo src/.libs/* src/*.la COMMA=, test: gen_tile_test ./gen_tile_test all-local: $(APXS) -c $(DEF_LDLIBS) $(AM_CFLAGS) \ $(subst -pthread,-Wc$(COMMA)-pthread,$(GLIB_CFLAGS)) \ -I@srcdir@/includes $(AM_LDFLAGS) $(STORE_LDFLAGS) \ @srcdir@/src/mod_tile.c \ @srcdir@/src/sys_utils.c \ @srcdir@/src/store.c \ @srcdir@/src/store_file.c \ @srcdir@/src/store_file_utils.c \ @srcdir@/src/store_memcached.c \ @srcdir@/src/store_rados.c \ @srcdir@/src/store_ro_http_proxy.c \ @srcdir@/src/store_ro_composite.c \ @srcdir@/src/store_null.c \ @srcdir@/src/g_logger.c install-mod_tile: mkdir -p $(DESTDIR)`$(APXS) -q LIBEXECDIR` $(APXS) -S LIBEXECDIR=$(DESTDIR)`$(APXS) \ -q LIBEXECDIR` -c -i $(DEF_LDLIBS) $(AM_CFLAGS) \ $(subst -pthread,-Wc$(COMMA)-pthread,$(GLIB_CFLAGS)) \ -I@srcdir@/includes $(AM_LDFLAGS) $(STORE_LDFLAGS) \ @srcdir@/src/mod_tile.c \ @srcdir@/src/sys_utils.c \ @srcdir@/src/store.c \ @srcdir@/src/store_file.c \ @srcdir@/src/store_file_utils.c \ @srcdir@/src/store_memcached.c \ @srcdir@/src/store_rados.c \ @srcdir@/src/store_ro_http_proxy.c \ @srcdir@/src/store_ro_composite.c \ @srcdir@/src/store_null.c \ @srcdir@/src/g_logger.c mod_tile-0.6.1/README.rst000066400000000000000000000171171410674543400150200ustar00rootroot00000000000000==================== mod_tile and renderd ==================== This software contains two main pieces: 1) ``mod_tile``: An Apache 2 module to deliver map tiles. 2) ``renderd``: A daemon that renders map tiles using mapnik. .. figure:: ./screenshot.jpg :alt: Image shoing example slippy map and OSM layer Together they efficiently render and serve raster map tiles for example to use within a slippy map. The two consist of the classic raster tile stack from `OpenStreetMap.org `__. As an alternative to ``renderd`` its drop-in replacement `Tirex `__ can be used in combination with ``mod_tile``. Dependencies ------------ * `GNU/Linux` Operating System (works best on Debian or Ubuntu) * `Apache 2 HTTP webserver `__ * `Mapnik `__ * `Cairo 2D graphics library `__ * `Curl library (SSL variant) `__ * `Iniparser library `__ * `GLib library `__ Installation ------------ Starting from the following operation systems and their versions: * Debian 11 (Bullseye) * Ubuntu 21.04 (Hirsute Hippo) the software and all dependencies can be installed simply with: :: $ apt install libapache2-mod-tile renderd These packages for **Debian** and **Ubuntu** are being maintained by the `Debian GIS Team `__ in the respective `repository `__. Compilation ----------- You may want to compile this software yourself. Either for developing on it or when using it on an operating system this is not being packaged for. We prepared instructions for you on how to build the software on the following distributions: * `CentOS 7 `__ * `Fedora 34 `__ * `Ubuntu 20.04 `__ (this should work as well for Debian 10) Configuration ------------- After you either installed the software packages or copiled the software yourself, you can continue with the configuration. For your convenience example configuration files are distributed with the software packages and located in the ``etc`` directory of this repository. A very basic example-map and data can be found in the ``utils/example-map`` directory. For a simple test copy it over to ``/var/www/example-map``. Copy the configuration files to their place, too: :: $ cp etc/renderd/renderd.conf /etc/renderd.conf $ cp etc/apache2/renderd.conf /etc/apache2/conf-available/renderd.conf $ cp etc/apache2/renderd-example-map.conf /etc/apache2/conf-available/renderd-example-map.conf Enable the configuration: :: $ sudo a2enmod tile $ sudo a2enconf renderd $ sudo a2enconf renderd-example-map Restart apache2: :: $ sudo a2enmod tile $ sudo a2enconf renderd And run the rendering daemon :: $ renderd -f Make sure the ``/var/cache/renderd/tiles`` directory is writable by the user running the renderd process. Try loading a tile in your browser, e.g. :: http://localhost/renderd-example/tiles/0/0/0.png You may edit ``/etc/renderd.conf`` to indicate the location of different mapnik style sheets (up to ten) and the endpoints you wish to use to access it. It is recommended to checkout `switch2osm `__ for nice tutorials on how to set up a full tile server like on `OpenStreetMap.org `__, using this software together with a `PostgreSQL `__ database and data from OpenStreetMap. Details about ``renderd``: Tile rendering ----------------------------------------- The rendering is implemented in a multithreaded process called ``renderd`` which opens either a unix or tcp socket and listens for requests to render tiles. It uses Mapnik to render tiles using the rendering rules defined in the configuration file ``/etc/renderd.conf``. Its configuration also allows to specify the number of rendering threads. The render daemon implements a queuing mechanism with multiple priority levels to provide an as up-to-date viewing experience given the available rendering resources. The highest priority is for on the fly rendering of tiles not yet in the tile cache, two priority levels for re-rendering out of date tiles on the fly and two background batch rendering queues. The on the fly rendering queues are limited to a short 32 metatile size to minimize latency. The size of the main background queue is determined at compile time, see: ``render_config.h`` Details about ``mod_tile``: Tile serving ---------------------------------------- An Apache module called ``mod_tile`` enhances the regular Apache file serving mechanisms to provide: 1) When tiles have expired it requests the rendering daemon to render (or re-render) the tile. 2) Remapping of the file path to the hashed layout. 3) Prioritizes rendering requests depending on the available resources on the server and how out of date they are. 4) Use tile storage other than a plain posix file system. e.g it can store tiles in a ceph object store, or proxy them from another tile server. 5) Tile expiry. It estimates when the tile is next likely to be rendered and adds the appropriate HTTP cache expiry headers. This is a configurable heuristic. To avoid problems with directories becoming too large and to avoid too many tiny files. They store the rendered tiles in "meta tiles" in a special hashed directory structure. These combine 8x8 actual tiles into a single metatile file. This is a more efficient use of disk space and inodes. The metatiles are then stored in the following directory structure: ``/[base_dir]/[TileSetName]/[Z]/[xxxxyyyy]/[xxxxyyyy]/[xxxxyyyy]/[xxxxyyyy]/[xxxxyyyy].png`` Where ``base_dir`` is a configurable base path for all tiles. ``TileSetName`` is the name of the style sheet rendered. ``Z`` is the zoom level. ``[xxxxyyyy]`` is an 8 bit number, with the first 4 bits taken from the x coordinate and the second 4 bits taken from the y coordinate. This attempts to cluster 16x16 square of tiles together into a single sub directory for more efficient access patterns. Apache serves the files as if they were present under ``/[TileSetName]/Z/X/Y.png`` with the path being converted automatically. Notes about performance ----------------------- ``mod_tile`` is designed for high performance tile serving. If the underlying disk system allows it, it can easily provide > 10k tiles/s on a single serve. Rendering performance is mostly dependent on mapnik and postgis performance, however ``renderd`` tries to make sure it uses underlying hardware as efficiently as possible and scales well on multi core systems. ``renderd`` also provides built-in features to scale to multi server rendering set-ups. Copyright and copyleft ---------------------- Copyright (c) 2007 - 2021 by mod_tile contributors (see `AUTHORS <./AUTHORS>`__) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. See the `COPYING <./COPYING>`__ for the full license text. mod_tile-0.6.1/autogen.sh000077500000000000000000000000311410674543400153150ustar00rootroot00000000000000#!/bin/sh autoreconf -vfimod_tile-0.6.1/configure.ac000066400000000000000000000043101410674543400156060ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.61]) AX_CONFIG_NICE AC_INIT(mod_tile, 0.1, http://trac.openstreetmap.org) AM_INIT_AUTOMAKE([subdir-objects]) LT_INIT AC_CONFIG_SRCDIR([src/convert_meta.c]) AC_CONFIG_HEADERS([includes/config.h]) AC_CONFIG_MACRO_DIR([m4]) # Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_CC_C99 dnl Find C++ compiler AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no) if test "$HAVE_CXX" = "no" then AC_MSG_ERROR([Could not find a c++ compiler]); fi # Checks for libraries. PKG_CHECK_MODULES([GLIB], [glib-2.0]) # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h syslog.h unistd.h utime.h paths.h sys/cdefs.h sys/loadavg.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_MODE_T AC_TYPE_SIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MKTIME AX_PTHREAD(,[AC_MSG_ERROR([no])]) AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(inet_ntoa, nsl) AC_SEARCH_LIBS(gethostbyname, resolv nsl) AC_SEARCH_LIBS(pow,m) AC_SEARCH_LIBS(clock_gettime,[rt posix4]) AX_LIB_MAPNIK AX_ENABLE_LIBMEMCACHED LIBCURL_CHECK_CONFIG AC_CHECK_LIB(rados, rados_version, [ AC_DEFINE([HAVE_LIBRADOS], [1], [Have found librados]) LIBRADOS_LDFLAGS='-lrados' AC_SUBST(LIBRADOS_LDFLAGS) ][]) AC_CHECK_FUNCS([bzero gethostbyname gettimeofday inet_ntoa memset mkdir pow select socket strchr strdup strerror strrchr strstr strtol strtoul utime],[],[AC_MSG_ERROR([One of the required functions was not found])]) AC_CHECK_FUNCS([daemon getloadavg],[],[]) AC_ARG_WITH(apxs, [ --with-apxs=PATH path to Apache apxs], [ if test "$withval" = "yes"; then AC_CHECK_PROGS(APXS, apxs apxs2 /opt/local/apache2/bin/apxs, reject) else APXS=$withval AC_SUBST(APXS) fi ], [ AC_CHECK_PROGS(APXS, apxs apxs2 /opt/local/apache2/bin/apxs, reject) ]) if test "$APXS" = "reject"; then AC_MSG_ERROR([Could not find apxs on the path.]) fi AC_CONFIG_FILES(Makefile) AC_OUTPUT mod_tile-0.6.1/docs/000077500000000000000000000000001410674543400142525ustar00rootroot00000000000000mod_tile-0.6.1/docs/build/000077500000000000000000000000001410674543400153515ustar00rootroot00000000000000mod_tile-0.6.1/docs/build/building_on_centos_7.md000066400000000000000000000077051410674543400217760ustar00rootroot00000000000000# Building on CentOS 7 This documents step by step on how to compile and put into use the software `mod_tile` and `renderd`. Please see our [Continous Integration script](../../.github/workflows/build-and-test-centos-7.yml) for more detail. As `CentOS 7` does not provide any `mapnik`/`mapnik-devel` packages in the official repository (nor are any available from `EPEL`,) it must therefore be built and installed before `mod_tile` can be built. Although `boost-devel` is present in the official repository, the version available there (`1.53.0`) is not in [mapnik's recommended dependency list](https://github.com/mapnik/mapnik/blob/v3.0.24/INSTALL.md#depends), so the `boost169-devel` package from `EPEL` should probably be used instead. ```shell #!/usr/bin/env bash export LD_LIBRARY_PATH=/usr/local/lib export MAPNIK_VERSION=3.0.24 # Install `EPEL` yum repository sudo yum --assumeyes install epel-release # Update installed packages sudo yum --assumeyes update # Install "Development Tools" group sudo yum --assumeyes groups install \ "Development Tools" # Install build dependencies sudo yum --assumeyes install \ boost169-devel \ cairo-devel \ freetype-devel \ gdal-devel \ glib2-devel \ harfbuzz-devel \ httpd-devel \ iniparser-devel \ libcurl-devel \ libicu-devel \ libjpeg-turbo-devel \ libmemcached-devel \ libpng-devel \ librados2-devel \ libtiff-devel \ libwebp-devel \ libxml2-devel \ postgresql-devel \ proj-devel \ sqlite-devel \ zlib-devel # Export `GDAL_DATA` & `PROJ_LIB` variables and create directories (if needed) export GDAL_DATA=$(gdal-config --datadir) export PROJ_LIB=/usr/share/proj sudo --preserve-env mkdir -p ${GDAL_DATA} ${PROJ_LIB} # Download, Build & Install `Mapnik` sudo mkdir -p /usr/local/src/mapnik-${MAPNIK_VERSION} cd /usr/local/src/mapnik-${MAPNIK_VERSION} sudo curl --silent --location https://github.com/mapnik/mapnik/releases/download/v${MAPNIK_VERSION}/mapnik-v${MAPNIK_VERSION}.tar.bz2 \ | sudo tar --verbose --extract --bzip2 --strip-components=1 --file=- sudo --preserve-env ./configure BOOST_INCLUDES=/usr/include/boost169 BOOST_LIBS=/usr/lib64/boost169 sudo --preserve-env JOBS=$(nproc) make sudo --preserve-env make install # Fix issue with `iniparser.h` from `iniparser-devel` not being in the expected location sudo mkdir /usr/include/iniparser sudo ln -s /usr/include/iniparser.h /usr/include/iniparser/iniparser.h # Download and build sudo git clone https://github.com/openstreetmap/mod_tile.git /usr/local/src/mod_tile cd /usr/local/src/mod_tile sudo --preserve-env ./autogen.sh sudo --preserve-env ./configure sudo --preserve-env make # Create tiles directory sudo mkdir --parents /run/renderd /var/cache/renderd/tiles # Move files of example map sudo cp -r "utils/example-map" /var/www/example-map # Install leaflet sudo curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" \ > /var/www/example-map/leaflet/leaflet.min.js sudo curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" \ > /var/www/example-map/leaflet/leaflet.css # Add configuration sudo cp "etc/renderd/renderd.conf.examples" /etc/renderd.conf sudo cp "etc/apache2/renderd.conf" /etc/httpd/conf.d/renderd.conf sudo cp "apache2/renderd-example-map.conf" \ /etc/httpd/conf.d/renderd-example-map.conf # Apply CentOS specific changes to configuration files sudo sed --in-place \ "s#/usr/lib/mapnik/3.0/input#/usr/lib64/mapnik/input#g" \ /etc/renderd.conf sudo sed --in-place \ "s#/usr/share/fonts/truetype#/usr/share/fonts#g" \ /etc/renderd.conf # Add and activate mod_tile for Apache echo "LoadModule tile_module /usr/lib64/httpd/modules/mod_tile.so" \ | sudo tee --append /etc/httpd/conf.modules.d/11-mod_tile.conf # Make example map the new main page of Apache sudo rm --force /etc/httpd/conf.d/welcome.conf # Install software sudo make install sudo make install-mod_tile # Start services sudo httpd sudo renderd -f ``` Then you can visit: `http://localhost/example-map` mod_tile-0.6.1/docs/build/building_on_fedora_34.md000066400000000000000000000043611410674543400220160ustar00rootroot00000000000000# Building on Fedora 34 This documents step by step on how to compile and put into use the software `mod_tile` and `renderd`. Please see our [Continous Integration script](../../.github/workflows/build-and-test-fedora-34.yml) for more detail. ```shell #!/usr/bin/env bash # Update installed packages sudo yum --assumeyes update # Install "Development Tools" group sudo yum --assumeyes groups install \ "Development Tools" \ "C Development Tools and Libraries" \ "Development Libraries" \ "Development Tools" # Install build dependencies sudo yum --assumeyes install \ cairo-devel \ glib2-devel \ httpd-devel \ iniparser-devel \ mapnik-devel \ libcurl-devel \ libmemcached-devel \ librados-devel # Download, Build & Install `mod_tile` git clone https://github.com/openstreetmap/mod_tile.git /usr/local/src/mod_tile cd /usr/local/src/mod_tile ./autogen.sh ./configure make # Create tiles directory sudo mkdir --parents /run/renderd /var/cache/renderd/tiles # Move files of example map sudo cp -r "utils/example-map" /var/www/example-map # Install leaflet sudo curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" \ > /var/www/example-map/leaflet/leaflet.min.js sudo curl --silent \ "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" \ > /var/www/example-map/leaflet/leaflet.css # Add configuration sudo cp "etc/renderd/renderd.conf.examples" /etc/renderd.conf sudo cp "etc/apache2/renderd.conf" /etc/httpd/conf.d/renderd.conf sudo cp "apache2/renderd-example-map.conf" \ /etc/httpd/conf.d/renderd-example-map.conf # Apply Fedora specific changes to configuration files sudo sed --in-place \ "s#/usr/lib/mapnik/3.0/input#/usr/lib64/mapnik/input#g" \ /etc/renderd.conf sudo sed --in-place \ "s#/usr/share/fonts/truetype#/usr/share/fonts#g" \ /etc/renderd.conf # Add and activate mod_tile for Apache echo "LoadModule tile_module /usr/lib64/httpd/modules/mod_tile.so" \ | sudo tee --append /etc/httpd/conf.modules.d/11-mod_tile.conf # Make example map the new main page of Apache sudo rm --force /etc/httpd/conf.d/welcome.conf # Install software sudo make install sudo make install-mod_tile # Start services sudo httpd sudo renderd -f ``` Then you can visit: `http://localhost/example-map` mod_tile-0.6.1/docs/build/building_on_ubuntu_20_04.md000066400000000000000000000032021410674543400223670ustar00rootroot00000000000000# Building on Ubuntu 20.04 This documents step by step on how to compile and put into use the software `mod_tile` and `renderd`. Please see our [Continous Integration script](../../.github/workflows/build-and-test-ubuntu-20-04.yml) for more detail. ```shell #!/usr/bin/env bash # Update installed packages sudo apt update && sudo apt upgrade --yes # Install build dependencies # (the last two are optional) sudo apt install build-essential \ autoconf \ apache2-dev \ libcairo2-dev \ libcurl4-gnutls-dev \ libglib2.0-dev \ libiniparser-dev \ libmapnik-dev \ libmemcached-dev \ librados-dev # Download, build & install git clone https://github.com/openstreetmap/mod_tile.git /usr/local/src/mod_tile cd /usr/local/src/mod_tile ./autogen.sh ./configure make # Create tiles directory sudo mkdir --parents /run/renderd /var/cache/renderd/tiles # Move files of example map sudo cp -r "utils/example-map" /var/www/example-map # Link leaflet library sudo ln --symbolic \ /usr/share/javascript/leaflet \ /var/www/example-map/leaflet # Add configuration sudo cp "etc/renderd/renderd.conf.examples" /etc/renderd.conf sudo cp "etc/apache2/renderd.conf" /etc/apach2/conf.d/renderd.conf sudo cp "etc/apache2/renderd-example-map.conf" \ /etc/apache2/conf-enabled/renderd-example-map.conf # Add and activate mod_tile for Apache echo "LoadModule tile_module /usr/lib/apache2/modules/mod_tile.so" \ | sudo tee --append /etc/apache2/mods-enabled/mod_tile.load # Install software sudo make install sudo make install-mod_tile # Start services sudo systemctl --now enable apache2 sudo renderd -f ``` Then you can visit: `http://localhost/example-map`mod_tile-0.6.1/docs/man/000077500000000000000000000000001410674543400150255ustar00rootroot00000000000000mod_tile-0.6.1/docs/man/convert_meta.1000066400000000000000000000027441410674543400176040ustar00rootroot00000000000000.TH CONVERT_META 1 "Jan 25, 2012" .\" Please adjust this date whenever revising the manpage. .SH NAME convert_meta \- A conversion program from .png map tiles to a more efficient conglomerate format (.meta). .SH SYNOPSIS .B convert_meta .RI [ options ] .br .SH DESCRIPTION This manual page documents briefly the .B convert_meta command. .PP .B convert_meta converts individual .png map tiles into the more efficient .meta file format. The .meta format stores a grid of 8x8 tiles in a single meta tile, reducing the number of files by a factor of 64. .PP .SH OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP \fB\-t\fR|\-\-tile-dir Specify the base directory where the tiles are stored. The default is /var/cache/renderd/tiles .TP \fB\-m\fR|\-\-map Specify the map style to convert. This specifies the full path to the files and is relative to the tile directory. The default is "default" and results in a full path of /var/cache/renderd/tiles/default to search for the tiles to convert .TP \fB\-u\fR|\-\-unpack Unpack the .meta files back to PNGs .TP \fB\-z\fR|\-\-min-zoom Specify the smallest zoom level to process. The default is 0. .TP \fB\-Z\fR|\-\-max-zoom Specify the largest zoom level up to which to process tiles. The default is 18. .PP .SH AUTHOR convert_meta was written by Jon Burgess and other OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/openstreetmap-tiles-update-expire.1000066400000000000000000000034261410674543400236720ustar00rootroot00000000000000.TH TILES-UPDATE-EXPIRE 1 "Apr 20, 2013" .\" Please adjust this date whenever revising the manpage. .SH NAME openstreetmap-tiles-update-expire \- updates a map database from the OSM diff stream. .SH SYNOPSIS .B openstreetmap-tiles-update-expire .RI [ YYYY-MM-DD ] .br .SH DESCRIPTION This manual page documents briefly the .B openstreetmap-tiles-update-expire command. .PP .B openstreetmap-tiles-update-expire is a helper script to keep a mod_tile based openstreetmap tile server up to date. It downloads a diff stream from OpenStreetMap using osmosis, then applies it to your database using osm2pgsql and finally marks changed tiles on disk as "dirty". .br Each time you call this script, it does one update cycle. If your db is further behind than the maximum duration for which osmosis is configured to fetch diffs, the db will not be fully up-to-date at the end of this script and it will be necessary to call it multiple times for a fully up-to-date database. .br This script can be used in conjunction with cron to automatically keep your database in sync with the OSM diff stream. .PP The first time this script needs to be called with a date to initialise the process. Thereafter, the script gets called without arguments. .PP .SH OPTIONS .TP \fBYYYY-MM-DD generation date of the planet file used for import. It initialises osmosis diff processing to this date. It is safe to set this date earlier than the actual date, as one can reapply diffs multiple times. This ensures that there is no missing data due to a gap between the generation of the planet file and the start of the diff processing. .PP .SH SEE ALSO .BR renderd (8), .BR mod_tile (1). .br .SH AUTHOR openstreetmap-tiles-update-expire was written by OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/render_expired.1000066400000000000000000000060171410674543400201120ustar00rootroot00000000000000.TH RENDER_EXPIRED 1 "Jan 27, 2012" .\" Please adjust this date whenever revising the manpage. .SH NAME render_expired \- expires a list of map tiles so that they get re-rendered. .SH SYNOPSIS .B render_expired .RI [ options ] < "expire.list" .br .SH DESCRIPTION This manual page documents briefly the .B render_expired command. .PP .B render_expired is a helper utility that takes a list of map tiles from stdin and expires them such that they will get re-rendered. Render_expired has three potential strategies of how to expire map tiles: .br 1) Render tiles directly: Render_expired can connect to the renderd socket and submit rendering requests for expired tiles directly .br 2) Delete tiles: Render_expired can delete expired tiles from disk. The next time the tile then gets viewed it will get re-rendered, assuming a dynamic rendering setup like mod_tile is installed .br 3) Mark tiles as dirty: A dynamic tile rendering system like mod_tile decides if a tile needs re-rendering by comparing the timestamp of the tile with the time of the planet-import-complet timestamp. Render_expired can set the timestamp of a tile back many years, ensuring it is older than the db import time, thus causeing the tile to be considered dirty and in need for re-render. .PP These three strategies can be combined and applied at different zoom levels. E.g. Zoom level 17-18 get deleted, z11 - z16 get marked dirty and z6 - z10 get rendered directly. .PP Render_expired takes a list of tiles from stdin which should be expired. The format of the list is one tile per line specified as z/x/y. .br 1/0/1 .br 1/1/1 .br 1/0/0 .br 1/1/0 .PP render_expired will automatically expand the list to cover the effected tiles at other zoom levels. .PP .SH OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP \fB\-m\fR|\-\-map=MAP Specify the style-sheet for which to expire tiles. The default is "default". .TP \fB\-s\fR|\-\-socket=SOCKET Specify the location of the renderd socket. .TP \fB\-n\fR|\-\-num-threads=N Specify the number of parallel requests to renderd. Should renderd have less threads active, requests will be queued. The default is 1. default if \fB\-\-append\fR is not specified. .TP \fB\-t\fR|\-\-tiledir=DIR Specify the base directory where the rendered tiles are. The default is '/var/cache/renderd/tiles' .TP \fB\-z\fR|\-\-min-zoom=ZOOM Filter input to only render tiles greater or equal to this zoom level (default is 0) .TP \fB\-Z\fR|\-\-max-zoom=ZOOM Filter input to only render tiles less than or equal to this zoom level (default is 18) .TP \fB\-d\fR|\-\-delete-from=ZOOM When expiring tiles of ZOOM or higher, delete them instead of re-rendering (default is off) .TP \fB\-T\fR|\-\-touch-from=ZOOM when expiring tiles of ZOOM or higher, touch them instead of re-rendering (default is off) .PP .SH SEE ALSO .BR renderd (1), .BR mod_tile (1). .br .SH AUTHOR render_expire was written by OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/render_list.1000066400000000000000000000041031410674543400174170ustar00rootroot00000000000000.TH RENDER_LIST 1 "Apr 25, 2013" .\" Please adjust this date whenever revising the manpage. .SH NAME render_list \- renders a list of map tiles by sending requests to a rendering daemon. .SH SYNOPSIS .B render_list .RI [ options ] < "render.list" .br .SH DESCRIPTION This manual page briefly documents the .B render_list command. .PP .B render_list is a helper utility that takes a list of map tiles from stdin and sends the requests to a rendering daemon .PP .SH OPTIONS This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP \fB\-a\fR|\-\-all Render all tiles in given zoom level range instead of reading from STDIN. .TP \fB\-f\fR|\-\-force Render tiles even if they seem current. .TP \fB\-m\fR|\-\-map=MAP Render tiles in this map (defaults to 'default'). .TP \fB\-l\fR|\-\-max-load=LOAD Sleep if load is this high (defaults to 16). .TP \fB\-s\fR|\-\-socket=SOCKET Unix domain socket name for contacting renderd. .TP \fB\-n\fR|\-\-num-threads=N The number of parallel request threads (default 1). .TP \fB\-t\fR|\-\-tile-dir Tile cache directory (defaults to '/var/cache/renderd/tiles'). .TP \fB\-z\fR|\-\-min-zoom=ZOOM Filter input to only render tiles greater or equal to this zoom level (default is 0). .TP \fB\-Z\fR|\-\-max-zoom=ZOOM Filter input to only render tiles less than or equal to this zoom level (default is 20). .PP If you are using --all, you can restrict the tile range by adding these options: .br -x, --min-x=X minimum X tile coordinate .br -X, --max-x=X maximum X tile coordinate .br -y, --min-y=Y minimum Y tile coordinate .br -Y, --max-y=Y maximum Y tile coordinate .PP Without --all, send a list of tiles to be rendered from STDIN in the format: .br X Y Z .br e.g. .br 0 0 1 .br 0 1 1 .br 1 0 1 .br 1 1 1 .br The above would cause all 4 tiles at zoom 1 to be rendered .SH SEE ALSO .BR renderd (8), .BR mod_tile (1). .br .SH AUTHOR render_list was written by OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/render_old.1000066400000000000000000000012011410674543400172160ustar00rootroot00000000000000.TH RENDER_OLD 1 "Mar 28, 2013" .\" Please adjust this date whenever revising the manpage. .SH NAME render_old \- renders a list of map tiles by sending requests to a rendering daemon. .SH SYNOPSIS .B render_list .RI [ options ] < "render.list" .br .SH DESCRIPTION This manual page documents briefly the .B render_old command. .PP .B render_old is a helper utility that pre renders expired map tiles by sending appropriate requests to a rendering daemon .PP .SH SEE ALSO .BR renderd (8), .BR mod_tile (1). .br .SH AUTHOR render_expire was written by OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/render_speedtest.1000066400000000000000000000016071410674543400204520ustar00rootroot00000000000000.TH SPEEDTEST 1 "Jan 25, 2012" .\" Please adjust this date whenever revising the manpage. .SH NAME speedtest \- Benchmapr tile rendering with renderd. .SH SYNOPSIS .B speedtest .RI [ options ] .SH DESCRIPTION This manual page documents briefly the .B speedtest command. .PP .B speedtest renders a bunch of tiles at various zoom levels to benchmark the speed of the rendering. .PP .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP \fB\-s\fR|\-\-socket=SOCKET Specify the location of the renderd socket to connect to. .TP \fB\-m\fR|\-\-map=MAP Specify the rendering style to test. The default is "default" .PP .SH SEE ALSO .BR renderd (1), .br .SH AUTHOR speedtest was written by Jon Burgess and other OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/docs/man/renderd.1000066400000000000000000000030711410674543400165330ustar00rootroot00000000000000.TH RENDERD 1 "Jan 25, 2012" .\" Please adjust this date whenever revising the manpage. .SH NAME renderd \- Rendering daemon for rendering OpenStreetMap tiles. .SH SYNOPSIS .B renderd .RI [ options ] .br .SH DESCRIPTION This manual page documents briefly the .B renderd command. .PP .B renderd is a rendering daemon for map tiles with the mapnik library. It receives render requests on a socket. Renderd queues requests in a number of different queues to manage load while rendering the requests with the mapnik library. By default renderd will start as a daemon. It will log information in the syslog. .PP .SH OPTIONS This programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP \fB\-f\fR|\-\-foreground Run renderd in the foreground for debugging purposes. .TP \fB\-c\fR|\-\-config Set the location of the config file used to configure the various parameters of renderd, like the mapnik style sheet. The default is /etc/renderd.conf .TP \fB\-s\fR|\-\-slave Renderd can be used in a distributed fashion across multiple rendering servers. The master renderd handles queuing and passes requests to the slaves. This parameter specifies which of the slave sections of renderd.conf applies to this instance of renderd. The default is to use the master section .TP \fB\-h\fR|\-\-help Print out a help text for renderd .PP .SH SEE ALSO .BR renderd.conf (1), .br .SH AUTHOR renderd was written by Jon Burgess, and other OpenStreetMap project members. .PP This manual page was written by OpenStreetMap authors. mod_tile-0.6.1/etc/000077500000000000000000000000001410674543400140755ustar00rootroot00000000000000mod_tile-0.6.1/etc/apache2/000077500000000000000000000000001410674543400154005ustar00rootroot00000000000000mod_tile-0.6.1/etc/apache2/renderd-example-map.conf000066400000000000000000000002561410674543400221010ustar00rootroot00000000000000Alias /renderd-example-map /var/www/example-map Options +FollowSymLinks AllowOverride All order allow,deny allow from all mod_tile-0.6.1/etc/apache2/renderd.conf000066400000000000000000000170161410674543400176770ustar00rootroot00000000000000 Options Indexes FollowSymLinks MultiViews AllowOverride None Require all granted ModTileTileDir /var/cache/renderd/tiles # You can manually configure each tile set with AddTileConfig or AddTileMimeConfig. # The first argument is the URL path relative to this virtual host # under which a tile set is served. The second argument specifies the # name of the tile set. This is used in the communication with renderd # and is the directory under which (meta)tiles are stored on disk. # # By default (AddTileConfig) mod_tile assumes you are serving png files, however, # mod_tile can also serve arbitrary other tile types such as javascript vector tiles, # assuming the backend render daemon can handle the file type. # To this purpose AddTileMimeConfig takes a 3rd agument, the file extension and it # will guess the correct mimetype from it. If the mime type is not set correctly automatically, # you need to use the configuration file route, where you can specify the mimetype and file extension # independently. # #AddTileConfig /folder/ TileSetName #AddTileMimeConfig /folder2/ TileSetName2 js # Alternatively (or in addition) you can load all the tile sets defined in the configuration file into this virtual host LoadTileConfigFile /etc/renderd.conf # Specify if mod_tile should keep tile delivery stats, which can be accessed from the URL /mod_tile # The default is On. As keeping stats needs to take a lock, this might have some performance impact, # but for nearly all intents and purposes this should be negligable and so it is safe to keep this turned on. ModTileEnableStats On # Turns on bulk mode. In bulk mode, mod_tile does not request any dirty tiles to be rerendered. Missing tiles # are always requested in the lowest priority. The default is Off. ModTileBulkMode Off # Timeout before giving up for a tile to be rendered ModTileRequestTimeout 3 # Timeout before giving up for a tile to be rendered that is otherwise missing ModTileMissingRequestTimeout 10 # If tile is out of date, don't re-render it if past this load threshold (users gets old tile) ModTileMaxLoadOld 2 # If tile is missing, don't render it if past this load threshold (user gets 404 error) ModTileMaxLoadMissing 5 # Socket where we connect to the rendering daemon ModTileRenderdSocketName /run/renderd/renderd.sock # Options controlling the cache proxy expiry headers. All values are in seconds. # # Caching is both important to reduce the load and bandwidth of the server, as # well as reduce the load time for the user. The site loads fastest if tiles can be # taken from the users browser cache and no round trip through the internet is needed. # With minutely or hourly updates, however there is a trade-off between cacheability # and freshness. As one can't predict the future, these are only heuristics, that # need tuning. # If there is a known update schedule such as only using weekly planet dumps to update the db, # this can also be taken into account through the constant PLANET_INTERVAL in render_config.h # but requires a recompile of mod_tile # The values in this sample configuration are not the same as the defaults # that apply if the config settings are left out. The defaults are more conservative # and disable most of the heuristics. # Caching is always a trade-off between being up to date and reducing server load or # client side latency and bandwidth requirements. Under some conditions, like poor # network conditions it might be more important to have good caching rather than the latest tiles. # Therefor the following config options allow to set a special hostheader for which the caching # behaviour is different to the normal heuristics # # The CacheExtended parameters overwrite all other caching parameters (including CacheDurationMax) # for tiles being requested via the hostname CacheExtendedHostname # #ModTileCacheExtendedHostname cache.tile.openstreetmap.org #ModTileCacheExtendedDuration 2592000 # Upper bound on the length a tile will be set cacheable, which takes # precedence over other settings of cacheing ModTileCacheDurationMax 604800 # Sets the time tiles can be cached for that are known to by outdated and have been # sent to renderd to be rerendered. This should be set to a value corresponding # roughly to how long it will take renderd to get through its queue. There is an additional # fuzz factor on top of this to not have all tiles expire at the same time ModTileCacheDurationDirty 900 # Specify the minimum time mod_tile will set the cache expiry to for fresh tiles. There # is an additional fuzz factor of between 0 and 3 hours on top of this. ModTileCacheDurationMinimum 10800 # Lower zoom levels are less likely to change noticeable, so these could be cached for longer # without users noticing much. # The heuristic offers three levels of zoom, Low, Medium and High, for which different minimum # cacheing times can be specified. #Specify the zoom level below which Medium starts and the time in seconds for which they can be cached ModTileCacheDurationMediumZoom 13 86400 #Specify the zoom level below which Low starts and the time in seconds for which they can be cached ModTileCacheDurationLowZoom 9 518400 # A further heuristic to determine cacheing times is when was the last time a tile has changed. # If it hasn't changed for a while, it is less likely to change in the immediate future, so the # tiles can be cached for longer. # For example, if the factor is 0.20 and the tile hasn't changed in the last 5 days, it can be cached # for up to one day without having to re-validate. ModTileCacheLastModifiedFactor 0.20 # Tile Throttling # Tile scrapers can often download large numbers of tiles and overly strain tileserver resources # mod_tile therefore offers the ability to automatically throttle requests from ip addresses that have # requested a lot of tiles. # The mechanism uses a token bucket approach to shape traffic. I.e. there is an initial pool of n tiles # per ip that can be requested arbitrarily fast. After that this pool gets filled up at a constant rate # The algorithm has two metrics. One based on overall tiles served to an ip address and a second one based on # the number of requests to renderd / tirex to render a new tile. # Overall enable or disable tile throttling ModTileEnableTileThrottling Off # Specify if you want to use the connecting IP for throtteling, or use the X-Forwarded-For header to determin the # 1 - use the client IP address, i.e. the first entry in the X-Forwarded-For list. This works through a cascade of proxies. # However, as the X-Forwarded-For is written by the client this is open to manipulation and can be used to circumvent the throttling # 2 - use the last specified IP in the X-Forwarded-For list. If you know all requests come through a reverse proxy # that adds an X-Forwarded-For header, you can trust this IP to be the IP the reverse proxy saw for the request ModTileEnableTileThrottlingXForward 0 # Parameters (poolsize in tiles and topup rate in tiles per second) for throttling tile serving. ModTileThrottlingTiles 10000 1 # Parameters (poolsize in tiles and topup rate in tiles per second) for throttling render requests. ModTileThrottlingRenders 128 0.2 mod_tile-0.6.1/etc/renderd/000077500000000000000000000000001410674543400155205ustar00rootroot00000000000000mod_tile-0.6.1/etc/renderd/renderd.conf000066400000000000000000000004451410674543400200150ustar00rootroot00000000000000; BASIC AND SIMPLE CONFIGURATION: [renderd] stats_file=/run/renderd/renderd.stats socketname=/run/renderd/renderd.sock num_threads=4 tile_dir=/var/cache/renderd/tiles [mapnik] plugins_dir=/usr/lib/mapnik/3.1/input font_dir=/usr/share/fonts/truetype font_dir_recurse=true ; ADD YOUR LAYERS: mod_tile-0.6.1/etc/renderd/renderd.conf.examples000066400000000000000000000040001410674543400216210ustar00rootroot00000000000000; EXAMPLES FOR BASIC CONFIGURATION OPTIONS [renderd] stats_file=/run/renderd/renderd.stats socketname=/run/renderd/renderd.sock num_threads=4 tile_dir=/var/cache/renderd/tiles ;[renderd] ;iphostname=::1 ;ipport=7654 ;num_threads=4 ;tile_dir=rados://tiles/etc/ceph/ceph.conf ;stats_file=/run/renderd/renderd.stats ;[renderd] ;iphostname=::1 ;ipport=7654 ;num_threads=8 ;tile_dir=memcached:// ;stats_file=/run/renderd/renderd.stats ; EXAMPLE FOR MAPNIK CONFIGURATION OPTION [mapnik] plugins_dir=/usr/lib/mapnik/3.0/input font_dir=/usr/share/fonts/truetype font_dir_recurse=true ; EXAMPLES FOR LAYER CONFIGURATION OPTIONS [example-map] URI=/renderd-example/tiles/ XML=/var/www/example-map/mapnik.xml ;[style1] ;URI=/osm_tiles/ ;TILEDIR=/var/cache/renderd/tiles ;XML=/usr/share/renderd/openstreetmap/osm-local.xml ;HOST=tile.openstreetmap.org ;TILESIZE=256 ;HTCPHOST=proxy.openstreetmap.org ;** config options used by mod_tile, but not renderd ** ;MINZOOM=0 ;MAXZOOM=18 ;TYPE=png image/png ;DESCRIPTION=This is a description of the tile layer used in the tile json request ;ATTRIBUTION=©OpenStreetMap and contributors, ODbL ;SERVER_ALIAS=http://localhost/ ;CORS=http://www.openstreetmap.org ;ASPECTX=1 ;ASPECTY=1 ;SCALE=1.0 ;[style2] ;URI=/osm_tiles2/ ;TILEDIR=rados://tiles/etc/ceph/ceph.conf ;TILESIZE=512 ;XML=/usr/share/renderd/openstreetmap/osm-local2.xml ;HOST=tile.openstreetmap.org ;HTCPHOST=proxy.openstreetmap.org ;** config options used by mod_tile, but not renderd ** ;MINZOOM=0 ;MAXZOOM=22 ;TYPE=png image/png ;DESCRIPTION=This is a description of the tile layer used in the tile json request ;ATTRIBUTION=©OpenStreetMap and contributors, ODbL ;SERVER_ALIAS=http://localhost/ ;CORS=* mod_tile-0.6.1/includes/000077500000000000000000000000001410674543400151305ustar00rootroot00000000000000mod_tile-0.6.1/includes/cache_expire.h000066400000000000000000000020101410674543400177110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 by mod_tile contributors (see AUTHORS file) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see http://www.gnu.org/licenses/. */ #ifndef CACHEEXPIRE_H #define CACHEEXPIRE_H #ifdef __cplusplus extern "C" { #endif #define HTCP_EXPIRE_CACHE 1 #define HTCP_EXPIRE_CACHE_PORT "4827" void cache_expire(int sock, char * host, char * uri, int x, int y, int z); int init_cache_expire(char * htcphost); #ifdef __cplusplus } #endif #endif mod_tile-0.6.1/includes/catch.hpp000066400000000000000000005433701410674543400167370ustar00rootroot00000000000000/* * Generated: 2013-02-19 08:44:57.311773 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * 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 TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic ignored "-Wglobal-constructors" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: internal/catch_notimplemented_exception.h #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #ifdef __GNUC__ #define CATCH_ATTRIBUTE_NORETURN __attribute__ ((noreturn)) #else #define CATCH_ATTRIBUTE_NORETURN #endif #include #include #include namespace Catch { class NonCopyable { NonCopyable(const NonCopyable&); void operator = (const NonCopyable&); protected: NonCopyable() {} virtual ~NonCopyable(); }; class SafeBool { public: typedef void (SafeBool::*type)() const; static type makeSafe(bool value) { return value ? &SafeBool::trueValue : 0; } private: void trueValue() const {} }; template inline void deleteAll(ContainerT& container) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for (; it != itEnd; ++it) { delete *it; } } template inline void deleteAllValues(AssociativeContainerT& container) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for (; it != itEnd; ++it) { delete it->second; } } template inline void forEach(ContainerT& container, Function function) { std::for_each(container.begin(), container.end(), function); } template inline void forEach(const ContainerT& container, Function function) { std::for_each(container.begin(), container.end(), function); } inline bool startsWith(const std::string& s, const std::string& prefix) { return s.size() >= prefix.size() && s.substr(0, prefix.size()) == prefix; } inline bool endsWith(const std::string& s, const std::string& suffix) { return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix; } inline bool contains(const std::string& s, const std::string& infix) { return s.find(infix) != std::string::npos; } struct pluralise { pluralise(std::size_t count, const std::string& label) : m_count(count), m_label(label) {} friend std::ostream& operator << (std::ostream& os, const pluralise& pluraliser) { os << pluraliser.m_count << " " << pluraliser.m_label; if (pluraliser.m_count != 1) { os << "s"; } return os; } std::size_t m_count; std::string m_label; }; struct SourceLineInfo { SourceLineInfo() : line(0) {} SourceLineInfo(const std::string& _file, std::size_t _line) : file(_file), line(_line) {} SourceLineInfo(const SourceLineInfo& other) : file(other.file), line(other.line) {} bool empty() const { return file.empty(); } std::string file; std::size_t line; }; inline std::ostream& operator << (std::ostream& os, const SourceLineInfo& info) { #ifndef __GNUG__ os << info.file << "(" << info.line << "): "; #else os << info.file << ":" << info.line << ": "; #endif return os; } CATCH_ATTRIBUTE_NORETURN inline void throwLogicError(const std::string& message, const SourceLineInfo& locationInfo) { std::ostringstream oss; oss << "Internal Catch error: '" << message << "' at: " << locationInfo; throw std::logic_error(oss.str()); } } #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); #include namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException(const SourceLineInfo& lineInfo); virtual ~NotImplementedException() throw() {} virtual const char* what() const throw(); private: std::string m_what; SourceLineInfo m_lineInfo; }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) // #included from: internal/catch_context.h #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED // #included from: catch_interfaces_generators.h #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED #include namespace Catch { struct IGeneratorInfo { virtual ~IGeneratorInfo(); virtual bool moveNext() = 0; virtual std::size_t getCurrentIndex() const = 0; }; struct IGeneratorsForTest { virtual ~IGeneratorsForTest(); virtual IGeneratorInfo& getGeneratorInfo(const std::string& fileInfo, std::size_t size) = 0; virtual bool moveNext() = 0; }; IGeneratorsForTest* createGeneratorsForTest(); } // end namespace Catch #include #include #include namespace Catch { class TestCaseInfo; class Stream; struct IResultCapture; struct IRunner; struct IGeneratorsForTest; struct IConfig; struct IContext { virtual ~IContext(); virtual IResultCapture& getResultCapture() = 0; virtual IRunner& getRunner() = 0; virtual size_t getGeneratorIndex(const std::string& fileInfo, size_t totalSize) = 0; virtual bool advanceGeneratorsForCurrentTest() = 0; virtual const IConfig* getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture(IResultCapture* resultCapture) = 0; virtual void setRunner(IRunner* runner) = 0; virtual void setConfig(const IConfig* config) = 0; }; IContext& getCurrentContext(); IMutableContext& getCurrentMutableContext(); void cleanUpContext(); Stream createStream(const std::string& streamName); } // #included from: internal/catch_test_registry.hpp #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED // #included from: catch_interfaces_testcase.h #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED // #included from: catch_ptr.hpp #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED namespace Catch { // An intrusive reference counting smart pointer. // T must implement addRef() and release() methods // typically implementing the IShared interface template class Ptr { public: Ptr() : m_p(NULL) {} Ptr(T* p) : m_p(p) { if (m_p) { m_p->addRef(); } } Ptr(const Ptr& other) : m_p(other.m_p) { if (m_p) { m_p->addRef(); } } ~Ptr() { if (m_p) { m_p->release(); } } Ptr& operator = (T* p) { Ptr temp(p); swap(temp); return *this; } Ptr& operator = (const Ptr& other) { Ptr temp(other); swap(temp); return *this; } void swap(Ptr& other) { std::swap(m_p, other.m_p); } T* get() { return m_p; } const T* get() const { return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == NULL; } private: T* m_p; }; struct IShared : NonCopyable { virtual ~IShared(); virtual void addRef() = 0; virtual void release() = 0; }; template struct SharedImpl : T { SharedImpl() : m_rc(0) {} virtual void addRef() { ++m_rc; } virtual void release() { if (--m_rc == 0) { delete this; } } int m_rc; }; } // end namespace Catch #include namespace Catch { class TestCaseFilters; struct ITestCase : IShared { virtual void invoke() const = 0; protected: virtual ~ITestCase(); }; class TestCaseInfo; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual const std::vector& getAllTests() const = 0; virtual std::vector getMatchingTestCases(const std::string& rawTestSpec) const = 0; }; } namespace Catch { template class MethodTestCase : public SharedImpl { public: MethodTestCase(void (C::*method)()) : m_method(method) {} virtual void invoke() const { C obj; (obj.*m_method)(); } private: virtual ~MethodTestCase() {} void (C::*m_method)(); }; typedef void(*TestFunction)(); struct AutoReg { AutoReg(TestFunction function, const char* name, const char* description, const SourceLineInfo& lineInfo); template AutoReg(void (C::*method)(), const char* className, const char* name, const char* description, const SourceLineInfo& lineInfo) { registerTestCase(new MethodTestCase(method), className, name, description, lineInfo); } void registerTestCase(ITestCase* testCase, const char* className, const char* name, const char* description, const SourceLineInfo& lineInfo); ~AutoReg(); private: AutoReg(const AutoReg&); void operator= (const AutoReg&); }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )(); \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE_NORETURN( Name, Desc ) \ static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() CATCH_ATTRIBUTE_NORETURN; \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Name, Desc, CATCH_INTERNAL_LINEINFO ); } /////////////////////////////////////////////////////////////////////////////// #define TEST_CASE_METHOD( ClassName, TestName, Desc )\ namespace{ \ struct INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ ) : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test, #ClassName, TestName, Desc, CATCH_INTERNAL_LINEINFO ); \ } \ void INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test() // #included from: internal/catch_capture.hpp #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED // #included from: catch_expression_decomposer.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_DECOMPOSER_HPP_INCLUDED // #included from: catch_expression_lhs.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED // #included from: catch_expressionresult_builder.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_BUILDER_H_INCLUDED // #included from: catch_tostring.hpp #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED #include #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease(NSObject* obj); id performOptionalSelector(id obj, SEL sel); #if !CATCH_ARC_ENABLED inline void arcSafeRelease(NSObject* obj) { [obj release]; } inline id performOptionalSelector(id obj, SEL sel) { if ([obj respondsToSelector: sel]) { return [obj performSelector: sel]; } return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease(NSObject*) {} inline id performOptionalSelector(id obj, SEL sel) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if ([obj respondsToSelector: sel]) { return [obj performSelector: sel]; } #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif #endif namespace Catch { namespace Detail { struct NonStreamable { template NonStreamable(const T&) {} }; // If the type does not have its own << overload for ostream then // this one will be used instead inline std::ostream& operator << (std::ostream& ss, NonStreamable) { return ss << "{?}"; } template inline std::string makeString(const T& value) { std::ostringstream oss; oss << value; return oss.str(); } template inline std::string makeString(T* p) { if (!p) { return INTERNAL_CATCH_STRINGIFY(NULL); } std::ostringstream oss; oss << p; return oss.str(); } template inline std::string makeString(const T* p) { if (!p) { return INTERNAL_CATCH_STRINGIFY(NULL); } std::ostringstream oss; oss << p; return oss.str(); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template std::string toString(const T& value) { return Detail::makeString(value); } // Built in overloads inline std::string toString(const std::string& value) { return "\"" + value + "\""; } inline std::string toString(const std::wstring& value) { std::ostringstream oss; oss << "\""; for (size_t i = 0; i < value.size(); ++i) { oss << static_cast(value[i] <= 0xff ? value[i] : '?'); } oss << "\""; return oss.str(); } inline std::string toString(const char* const value) { return value ? Catch::toString(std::string(value)) : std::string("{null string}"); } inline std::string toString(char* const value) { return Catch::toString(static_cast(value)); } inline std::string toString(int value) { std::ostringstream oss; oss << value; return oss.str(); } inline std::string toString(unsigned long value) { std::ostringstream oss; if (value > 8192) { oss << "0x" << std::hex << value; } else { oss << value; } return oss.str(); } inline std::string toString(unsigned int value) { return toString(static_cast(value)); } inline std::string toString(const double value) { std::ostringstream oss; oss << value; return oss.str(); } inline std::string toString(bool value) { return value ? "true" : "false"; } inline std::string toString(char value) { return value < ' ' ? toString((unsigned int)value) : Detail::makeString(value); } inline std::string toString(signed char value) { return toString(static_cast(value)); } #ifdef CATCH_CONFIG_CPP11_NULLPTR inline std::string toString(std::nullptr_t) { return "nullptr"; } #endif #ifdef __OBJC__ inline std::string toString(NSString const * const& nsstring) { return std::string("@\"") + [nsstring UTF8String] + "\""; } inline std::string toString(NSString * CATCH_ARC_STRONG const& nsstring) { return std::string("@\"") + [nsstring UTF8String] + "\""; } inline std::string toString(NSObject* const& nsObject) { return toString([nsObject description]); } #endif } // end namespace Catch // #included from: catch_assertionresult.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include // #included from: catch_result_type.h #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2 }; }; inline bool isOk(ResultWas::OfType resultType) { return (resultType & ResultWas::FailureBit) == 0; } // ResultAction::Value enum struct ResultAction { enum Value { None, Failed = 1, // Failure - but no debug break if Debug bit not set Debug = 2, // If this bit is set, invoke the debugger Abort = 4 // Test run should abort }; }; // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x00, ContinueOnFailure = 0x01, // Failures fail test, but execution continues NegateResult = 0x02, // Prefix expressiom with ! SuppressFail = 0x04 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | (ResultDisposition::Flags lhs, ResultDisposition::Flags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } inline bool shouldContinueOnFailure(int flags) { return flags & ResultDisposition::ContinueOnFailure; } inline bool shouldNegate(int flags) { return flags & ResultDisposition::NegateResult; } inline bool shouldSuppressFailure(int flags) { return flags & ResultDisposition::SuppressFail; } } // end namespace Catch namespace Catch { struct AssertionInfo { AssertionInfo() {} AssertionInfo(const std::string& _macroName, const SourceLineInfo& _lineInfo, const std::string& _capturedExpression, ResultDisposition::Flags _resultDisposition); std::string macroName; SourceLineInfo lineInfo; std::string capturedExpression; ResultDisposition::Flags resultDisposition; }; struct AssertionResultData { AssertionResultData() : resultType(ResultWas::Unknown) {} std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; }; class AssertionResult { public: AssertionResult(); AssertionResult(const AssertionInfo& info, const AssertionResultData& data); ~AssertionResult(); bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch // #included from: catch_evaluate.hpp #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits { static const char* getName() { return "*error*"; } }; template<> struct OperatorTraits { static const char* getName() { return "=="; } }; template<> struct OperatorTraits { static const char* getName() { return "!="; } }; template<> struct OperatorTraits { static const char* getName() { return "<"; } }; template<> struct OperatorTraits { static const char* getName() { return ">"; } }; template<> struct OperatorTraits { static const char* getName() { return "<="; } }; template<> struct OperatorTraits { static const char* getName() { return ">="; } }; // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template class Evaluator {}; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) == const_cast(rhs); } }; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) != const_cast(rhs); } }; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) < const_cast(rhs); } }; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) > const_cast(rhs); } }; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) >= const_cast(rhs); } }; template struct Evaluator { static bool evaluate(const T1& lhs, const T2& rhs) { return const_cast(lhs) <= const_cast(rhs); } }; template bool applyEvaluator(const T1& lhs, const T2& rhs) { return Evaluator::evaluate(lhs, rhs); } // This level of indirection allows us to specialise for integer types // to avoid signed/ unsigned warnings // "base" overload template bool compare(const T1& lhs, const T2& rhs) { return Evaluator::evaluate(lhs, rhs); } // unsigned X to int template bool compare(unsigned int lhs, int rhs) { return applyEvaluator(lhs, static_cast(rhs)); } template bool compare(unsigned long lhs, int rhs) { return applyEvaluator(lhs, static_cast(rhs)); } template bool compare(unsigned char lhs, int rhs) { return applyEvaluator(lhs, static_cast(rhs)); } // unsigned X to long template bool compare(unsigned int lhs, long rhs) { return applyEvaluator(lhs, static_cast(rhs)); } template bool compare(unsigned long lhs, long rhs) { return applyEvaluator(lhs, static_cast(rhs)); } template bool compare(unsigned char lhs, long rhs) { return applyEvaluator(lhs, static_cast(rhs)); } // int to unsigned X template bool compare(int lhs, unsigned int rhs) { return applyEvaluator(static_cast(lhs), rhs); } template bool compare(int lhs, unsigned long rhs) { return applyEvaluator(static_cast(lhs), rhs); } template bool compare(int lhs, unsigned char rhs) { return applyEvaluator(static_cast(lhs), rhs); } // long to unsigned X template bool compare(long lhs, unsigned int rhs) { return applyEvaluator(static_cast(lhs), rhs); } template bool compare(long lhs, unsigned long rhs) { return applyEvaluator(static_cast(lhs), rhs); } template bool compare(long lhs, unsigned char rhs) { return applyEvaluator(static_cast(lhs), rhs); } // pointer to long (when comparing against NULL) template bool compare(long lhs, T* rhs) { return Evaluator::evaluate(reinterpret_cast(lhs), rhs); } template bool compare(T* lhs, long rhs) { return Evaluator::evaluate(lhs, reinterpret_cast(rhs)); } // pointer to int (when comparing against NULL) template bool compare(int lhs, T* rhs) { return Evaluator::evaluate(reinterpret_cast(lhs), rhs); } template bool compare(T* lhs, int rhs) { return Evaluator::evaluate(lhs, reinterpret_cast(rhs)); } } // end of namespace Internal } // end of namespace Catch namespace Catch { // Wraps the (stringised versions of) the lhs, operator and rhs of an expression - as well as // the result of evaluating it. This is used to build an AssertionResult object class ExpressionResultBuilder { public: ExpressionResultBuilder(ResultWas::OfType resultType = ResultWas::Unknown); ExpressionResultBuilder(const ExpressionResultBuilder& other); ExpressionResultBuilder& operator=(const ExpressionResultBuilder& other); ExpressionResultBuilder& setResultType(ResultWas::OfType result); ExpressionResultBuilder& setResultType(bool result); ExpressionResultBuilder& setLhs(const std::string& lhs); ExpressionResultBuilder& setRhs(const std::string& rhs); ExpressionResultBuilder& setOp(const std::string& op); ExpressionResultBuilder& endExpression(ResultDisposition::Flags resultDisposition); template ExpressionResultBuilder& operator << (const T& value) { m_stream << value; return *this; } std::string reconstructExpression(const AssertionInfo& info) const; AssertionResult buildResult(const AssertionInfo& info) const; private: AssertionResultData m_data; struct ExprComponents { ExprComponents() : shouldNegate(false) {} bool shouldNegate; std::string lhs, rhs, op; } m_exprComponents; std::ostringstream m_stream; }; } // end namespace Catch namespace Catch { struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; // Wraps the LHS of an expression and captures the operator and RHS (if any) - wrapping them all // in an ExpressionResultBuilder object template class ExpressionLhs { void operator = (const ExpressionLhs&); public: ExpressionLhs(T lhs) : m_lhs(lhs) {} template ExpressionResultBuilder& operator == (const RhsT& rhs) { return captureExpression(rhs); } template ExpressionResultBuilder& operator != (const RhsT& rhs) { return captureExpression(rhs); } template ExpressionResultBuilder& operator < (const RhsT& rhs) { return captureExpression(rhs); } template ExpressionResultBuilder& operator > (const RhsT& rhs) { return captureExpression(rhs); } template ExpressionResultBuilder& operator <= (const RhsT& rhs) { return captureExpression(rhs); } template ExpressionResultBuilder& operator >= (const RhsT& rhs) { return captureExpression(rhs); } ExpressionResultBuilder& operator == (bool rhs) { return captureExpression(rhs); } ExpressionResultBuilder& operator != (bool rhs) { return captureExpression(rhs); } ExpressionResultBuilder& endExpression(ResultDisposition::Flags resultDisposition) { bool value = m_lhs ? true : false; return m_result .setLhs(Catch::toString(value)) .setResultType(value) .endExpression(resultDisposition); } // Only simple binary expressions are allowed on the LHS. // If more complex compositions are required then place the sub expression in parentheses template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + (const RhsT&); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - (const RhsT&); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / (const RhsT&); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * (const RhsT&); private: template ExpressionResultBuilder& captureExpression(const RhsT& rhs) { return m_result .setResultType(Internal::compare(m_lhs, rhs)) .setLhs(Catch::toString(m_lhs)) .setRhs(Catch::toString(rhs)) .setOp(Internal::OperatorTraits::getName()); } private: ExpressionResultBuilder m_result; T m_lhs; }; } // end namespace Catch namespace Catch { // Captures the LHS of the expression and wraps it in an Expression Lhs object class ExpressionDecomposer { public: template ExpressionLhs operator->* (const T & operand) { return ExpressionLhs(operand); } ExpressionLhs operator->* (bool value) { return ExpressionLhs(value); } }; } // end namespace Catch // #included from: catch_interfaces_capture.h #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts() : passed(0), failed(0) {} Counts operator - (const Counts& other) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; return diff; } Counts& operator += (const Counts& other) { passed += other.passed; failed += other.failed; return *this; } std::size_t total() const { return passed + failed; } std::size_t passed; std::size_t failed; }; struct Totals { Totals operator - (const Totals& other) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals delta(const Totals& prevTotals) const { Totals diff = *this - prevTotals; if (diff.assertions.failed > 0) { ++diff.testCases.failed; } else { ++diff.testCases.passed; } return diff; } Totals& operator += (const Totals& other) { assertions += other.assertions; testCases += other.testCases; return *this; } Counts assertions; Counts testCases; }; } namespace Catch { class TestCaseInfo; class ScopedInfo; class ExpressionResultBuilder; class AssertionResult; struct AssertionInfo; struct IResultCapture { virtual ~IResultCapture(); virtual void testEnded(const AssertionResult& result) = 0; virtual bool sectionStarted(const std::string& name, const std::string& description, const SourceLineInfo& lineInfo, Counts& assertions) = 0; virtual void sectionEnded(const std::string& name, const Counts& assertions) = 0; virtual void pushScopedInfo(ScopedInfo* scopedInfo) = 0; virtual void popScopedInfo(ScopedInfo* scopedInfo) = 0; virtual bool shouldDebugBreak() const = 0; virtual ResultAction::Value acceptExpression(const ExpressionResultBuilder& assertionResult, const AssertionInfo& assertionInfo) = 0; virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; }; } // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #include #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_IPHONE #elif defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #define CATCH_PLATFORM_WINDOWS #endif #ifdef CATCH_PLATFORM_MAC #include #include #include #include #include namespace Catch { // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). inline bool isDebuggerActive() { int junk; int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); assert(junk == 0); // We're being debugged if the P_TRACED flag is set. return ((info.kp_proc.p_flag & P_TRACED) != 0); } } // The following code snippet taken from: // http://cocoawithlove.com/2008/03/break-into-debugger.html #ifdef DEBUG #if defined(__ppc64__) || defined(__ppc__) #define BreakIntoDebugger() \ if( Catch::isDebuggerActive() ) { \ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ : : : "memory","r0","r3","r4" ); \ } #else #define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} #endif #else inline void BreakIntoDebugger() {} #endif #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); #define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); } inline bool isDebuggerActive() { return IsDebuggerPresent() != 0; } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); } inline bool isDebuggerActive() { return IsDebuggerPresent() != 0; } #else inline void BreakIntoDebugger() {} inline bool isDebuggerActive() { return false; } #endif #ifdef CATCH_PLATFORM_WINDOWS extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char*); inline void writeToDebugConsole(const std::string& text) { ::OutputDebugStringA(text.c_str()); } #else inline void writeToDebugConsole(const std::string& text) { // !TBD: Need a version for Mac/ XCode and other IDEs std::cout << text; } #endif // CATCH_PLATFORM_WINDOWS // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED // #included from: catch_interfaces_reporter.h #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED // #included from: catch_config.hpp #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED // #included from: catch_test_spec.h #define TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED // #included from: catch_test_case_info.h #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include #include namespace Catch { struct ITestCase; class TestCaseInfo { public: TestCaseInfo(); TestCaseInfo(ITestCase* testCase, const std::string& className, const std::string& name, const std::string& description, const SourceLineInfo& lineInfo); TestCaseInfo(const TestCaseInfo& other, const std::string& name); TestCaseInfo(const TestCaseInfo& other); void invoke() const; const std::string& getClassName() const; const std::string& getName() const; const std::string& getDescription() const; const SourceLineInfo& getLineInfo() const; bool isHidden() const; bool hasTag(const std::string& tag) const; bool matchesTags(const std::string& tagPattern) const; const std::set& getTags() const; void swap(TestCaseInfo& other); bool operator == (const TestCaseInfo& other) const; bool operator < (const TestCaseInfo& other) const; TestCaseInfo& operator = (const TestCaseInfo& other); private: Ptr m_test; std::string m_className; std::string m_name; std::string m_description; std::set m_tags; SourceLineInfo m_lineInfo; bool m_isHidden; }; } // #included from: catch_tags.hpp #define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED #include #include #include #include #ifdef __clang__ #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { class TagParser { public: virtual ~TagParser(); void parse(const std::string& str) { std::size_t pos = 0; while (pos < str.size()) { char c = str[pos]; if (c == '[') { std::size_t end = str.find_first_of(']', pos); if (end != std::string::npos) { acceptTag(str.substr(pos + 1, end - pos - 1)); pos = end + 1; } else { acceptChar(c); pos++; } } else { acceptChar(c); pos++; } } endParse(); } protected: virtual void acceptTag(const std::string& tag) = 0; virtual void acceptChar(char c) = 0; virtual void endParse() {} private: }; class TagExtracter : public TagParser { public: TagExtracter(std::set& tags) : m_tags(tags) {} virtual ~TagExtracter(); void parse(std::string& description) { TagParser::parse(description); description = m_remainder; } private: virtual void acceptTag(const std::string& tag) { m_tags.insert(tag); } virtual void acceptChar(char c) { m_remainder += c; } TagExtracter& operator=(const TagExtracter&); std::set& m_tags; std::string m_remainder; }; class Tag { public: Tag() : m_isNegated(false) {} Tag(const std::string& name, bool isNegated) : m_name(name), m_isNegated(isNegated) {} std::string getName() const { return m_name; } bool isNegated() const { return m_isNegated; } bool operator !() const { return m_name.empty(); } private: std::string m_name; bool m_isNegated; }; class TagSet { typedef std::map TagMap; public: void add(const Tag& tag) { m_tags.insert(std::make_pair(tag.getName(), tag)); } bool empty() const { return m_tags.empty(); } bool matches(const std::set& tags) const { TagMap::const_iterator it = m_tags.begin(); TagMap::const_iterator itEnd = m_tags.end(); for (; it != itEnd; ++it) { bool found = tags.find(it->first) != tags.end(); if (found == it->second.isNegated()) { return false; } } return true; } private: TagMap m_tags; }; class TagExpression { public: bool matches(const std::set& tags) const { std::vector::const_iterator it = m_tagSets.begin(); std::vector::const_iterator itEnd = m_tagSets.end(); for (; it != itEnd; ++it) if (it->matches(tags)) { return true; } return false; } private: friend class TagExpressionParser; std::vector m_tagSets; }; class TagExpressionParser : public TagParser { public: TagExpressionParser(TagExpression& exp) : m_isNegated(false), m_exp(exp) {} ~TagExpressionParser(); private: virtual void acceptTag(const std::string& tag) { m_currentTagSet.add(Tag(tag, m_isNegated)); m_isNegated = false; } virtual void acceptChar(char c) { switch (c) { case '~': m_isNegated = true; break; case ',': m_exp.m_tagSets.push_back(m_currentTagSet); break; } } virtual void endParse() { if (!m_currentTagSet.empty()) { m_exp.m_tagSets.push_back(m_currentTagSet); } } TagExpressionParser& operator=(const TagExpressionParser&); bool m_isNegated; TagSet m_currentTagSet; TagExpression& m_exp; }; } // end namespace Catch #include #include namespace Catch { struct IfFilterMatches { enum DoWhat { AutoDetectBehaviour, IncludeTests, ExcludeTests }; }; class TestCaseFilter { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: TestCaseFilter(const std::string& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour) : m_stringToMatch(testSpec), m_filterType(matchBehaviour), m_wildcardPosition(NoWildcard) { if (m_filterType == IfFilterMatches::AutoDetectBehaviour) { if (startsWith(m_stringToMatch, "exclude:")) { m_stringToMatch = m_stringToMatch.substr(8); m_filterType = IfFilterMatches::ExcludeTests; } else if (startsWith(m_stringToMatch, "~")) { m_stringToMatch = m_stringToMatch.substr(1); m_filterType = IfFilterMatches::ExcludeTests; } else { m_filterType = IfFilterMatches::IncludeTests; } } if (m_stringToMatch[0] == '*') { m_stringToMatch = m_stringToMatch.substr(1); m_wildcardPosition = (WildcardPosition)(m_wildcardPosition | WildcardAtStart); } if (m_stringToMatch[m_stringToMatch.size() - 1] == '*') { m_stringToMatch = m_stringToMatch.substr(0, m_stringToMatch.size() - 1); m_wildcardPosition = (WildcardPosition)(m_wildcardPosition | WildcardAtEnd); } } IfFilterMatches::DoWhat getFilterType() const { return m_filterType; } bool shouldInclude(const TestCaseInfo& testCase) const { return isMatch(testCase) == (m_filterType == IfFilterMatches::IncludeTests); } private: #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif bool isMatch(const TestCaseInfo& testCase) const { const std::string& name = testCase.getName(); switch (m_wildcardPosition) { case NoWildcard: return m_stringToMatch == name; case WildcardAtStart: return endsWith(name, m_stringToMatch); case WildcardAtEnd: return startsWith(name, m_stringToMatch); case WildcardAtBothEnds: return contains(name, m_stringToMatch); } throw std::logic_error("Unhandled wildcard type"); } #ifdef __clang__ #pragma clang diagnostic pop #endif std::string m_stringToMatch; IfFilterMatches::DoWhat m_filterType; WildcardPosition m_wildcardPosition; }; class TestCaseFilters { public: TestCaseFilters(const std::string& name) : m_name(name) {} std::string getName() const { return m_name; } void addFilter(const TestCaseFilter& filter) { if (filter.getFilterType() == IfFilterMatches::ExcludeTests) { m_exclusionFilters.push_back(filter); } else { m_inclusionFilters.push_back(filter); } } void addTags(const std::string& tagPattern) { TagExpression exp; TagExpressionParser(exp).parse(tagPattern); m_tagExpressions.push_back(exp); } bool shouldInclude(const TestCaseInfo& testCase) const { if (!m_tagExpressions.empty()) { std::vector::const_iterator it = m_tagExpressions.begin(); std::vector::const_iterator itEnd = m_tagExpressions.end(); for (; it != itEnd; ++it) if (it->matches(testCase.getTags())) { break; } if (it == itEnd) { return false; } } if (!m_inclusionFilters.empty()) { std::vector::const_iterator it = m_inclusionFilters.begin(); std::vector::const_iterator itEnd = m_inclusionFilters.end(); for (; it != itEnd; ++it) if (it->shouldInclude(testCase)) { break; } if (it == itEnd) { return false; } } else if (m_exclusionFilters.empty() && m_tagExpressions.empty()) { return !testCase.isHidden(); } std::vector::const_iterator it = m_exclusionFilters.begin(); std::vector::const_iterator itEnd = m_exclusionFilters.end(); for (; it != itEnd; ++it) if (!it->shouldInclude(testCase)) { return false; } return true; } private: std::vector m_tagExpressions; std::vector m_inclusionFilters; std::vector m_exclusionFilters; std::string m_name; }; } // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED namespace Catch { struct IConfig { virtual ~IConfig(); virtual bool allowThrows() const = 0; }; } // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED // #included from: catch_streambuf.h #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase(); }; } #include #include namespace Catch { template class StreamBufImpl : public StreamBufBase { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp(data, data + sizeof(data)); } ~StreamBufImpl() { sync(); } private: int overflow(int c) { sync(); if (c != EOF) { if (pbase() == epptr()) { m_writer(std::string(1, static_cast(c))); } else { sputc(static_cast(c)); } } return 0; } int sync() { if (pbase() != pptr()) { m_writer(std::string(pbase(), static_cast(pptr() - pbase()))); setp(pbase(), epptr()); } return 0; } }; /////////////////////////////////////////////////////////////////////////// struct OutputDebugWriter { void operator()(const std::string &str) { writeToDebugConsole(str); } }; class Stream { public: Stream() : streamBuf(NULL), isOwned(false) {} Stream(std::streambuf* _streamBuf, bool _isOwned) : streamBuf(_streamBuf), isOwned(_isOwned) {} void release() { if (isOwned) { delete streamBuf; streamBuf = NULL; isOwned = false; } } std::streambuf* streamBuf; private: bool isOwned; }; } #include #include #include #include namespace Catch { struct Include { enum WhichResults { FailedOnly, SuccessfulResults }; }; struct List { enum What { None = 0, Reports = 1, Tests = 2, All = 3, TestNames = 6, WhatMask = 0xf, AsText = 0x10, AsXml = 0x20, AsMask = 0xf0 }; }; struct ConfigData { struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01 }; }; ConfigData() : listSpec(List::None), shouldDebugBreak(false), includeWhichResults(Include::FailedOnly), cutoff(-1), allowThrows(true), warnings(WarnAbout::Nothing) {} std::string reporter; std::string outputFilename; List::What listSpec; std::vector filters; bool shouldDebugBreak; std::string stream; Include::WhichResults includeWhichResults; std::string name; int cutoff; bool allowThrows; WarnAbout::What warnings; }; class Config : public IConfig { private: Config(const Config& other); Config& operator = (const Config& other); virtual void dummy(); public: Config() : m_os(std::cout.rdbuf()) {} Config(const ConfigData& data) : m_data(data), m_os(std::cout.rdbuf()) {} virtual ~Config() { m_os.rdbuf(std::cout.rdbuf()); m_stream.release(); } void setFilename(const std::string& filename) { m_data.outputFilename = filename; } List::What getListSpec(void) const { return m_data.listSpec; } const std::string& getFilename() const { return m_data.outputFilename ; } List::What listWhat() const { return static_cast(m_data.listSpec & List::WhatMask); } List::What listAs() const { return static_cast(m_data.listSpec & List::AsMask); } std::string getName() const { return m_data.name; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } virtual std::ostream& stream() const { return m_os; } void setStreamBuf(std::streambuf* buf) { m_os.rdbuf(buf ? buf : std::cout.rdbuf()); } void useStream(const std::string& streamName) { Stream stream = createStream(streamName); setStreamBuf(stream.streamBuf); m_stream.release(); m_stream = stream; } void addTestSpec(const std::string& testSpec) { TestCaseFilters filters(testSpec); filters.addFilter(TestCaseFilter(testSpec)); m_data.filters.push_back(filters); } virtual bool includeSuccessfulResults() const { return m_data.includeWhichResults == Include::SuccessfulResults; } int getCutoff() const { return m_data.cutoff; } virtual bool allowThrows() const { return m_data.allowThrows; } const ConfigData& data() const { return m_data; } ConfigData& data() { return m_data; } private: ConfigData m_data; // !TBD Move these out of here Stream m_stream; mutable std::ostream m_os; }; } // end namespace Catch #include #include #include namespace Catch { struct ReporterConfig { ReporterConfig(const std::string& _name, std::ostream& _stream, bool _includeSuccessfulResults, const ConfigData& _fullConfig) : name(_name), stream(_stream), includeSuccessfulResults(_includeSuccessfulResults), fullConfig(_fullConfig) {} ReporterConfig(const ReporterConfig& other) : name(other.name), stream(other.stream), includeSuccessfulResults(other.includeSuccessfulResults), fullConfig(other.fullConfig) {} std::string name; std::ostream& stream; bool includeSuccessfulResults; ConfigData fullConfig; private: void operator=(const ReporterConfig&); }; class TestCaseInfo; class AssertionResult; struct IReporter : IShared { virtual ~IReporter(); virtual bool shouldRedirectStdout() const = 0; virtual void StartTesting() = 0; virtual void EndTesting(const Totals& totals) = 0; virtual void StartGroup(const std::string& groupName) = 0; virtual void EndGroup(const std::string& groupName, const Totals& totals) = 0; virtual void StartTestCase(const TestCaseInfo& testInfo) = 0; // TestCaseResult virtual void EndTestCase(const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr) = 0; // SectionInfo virtual void StartSection(const std::string& sectionName, const std::string& description) = 0; // Section Result virtual void EndSection(const std::string& sectionName, const Counts& assertions) = 0; // - merge into SectionResult ? virtual void NoAssertionsInSection(const std::string& sectionName) = 0; virtual void NoAssertionsInTestCase(const std::string& testName) = 0; // - merge into SectionResult, TestCaseResult, GroupResult & TestRunResult virtual void Aborted() = 0; // AssertionReslt virtual void Result(const AssertionResult& result) = 0; }; struct IReporterFactory { virtual ~IReporterFactory(); virtual IReporter* create(const ReporterConfig& config) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { typedef std::map FactoryMap; virtual ~IReporterRegistry(); virtual IReporter* create(const std::string& name, const ReporterConfig& config) const = 0; virtual const FactoryMap& getFactories() const = 0; }; inline std::string trim(const std::string& str) { std::string::size_type start = str.find_first_not_of("\n\r\t "); std::string::size_type end = str.find_last_not_of("\n\r\t "); return start != std::string::npos ? str.substr(start, 1 + end - start) : ""; } } #include namespace Catch { class TestCaseInfo; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IRegistryHub { virtual ~IRegistryHub(); virtual const IReporterRegistry& getReporterRegistry() const = 0; virtual const ITestCaseRegistry& getTestCaseRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter(const std::string& name, IReporterFactory* factory) = 0; virtual void registerTest(const TestCaseInfo& testInfo) = 0; virtual void registerTranslator(const IExceptionTranslator* translator) = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } #include namespace Catch { inline IResultCapture& getResultCapture() { return getCurrentContext().getResultCapture(); } template ExpressionResultBuilder expressionResultBuilderFromMatcher(const MatcherT& matcher, const std::string& matcherCallAsString) { std::string matcherAsString = matcher.toString(); if (matcherAsString == "{?}") { matcherAsString = matcherCallAsString; } return ExpressionResultBuilder() .setRhs(matcherAsString) .setOp("matches"); } template ExpressionResultBuilder expressionResultBuilderFromMatcher(const MatcherT& matcher, const ArgT& arg, const std::string& matcherCallAsString) { return expressionResultBuilderFromMatcher(matcher, matcherCallAsString) .setLhs(Catch::toString(arg)) .setResultType(matcher.match(arg)); } template ExpressionResultBuilder expressionResultBuilderFromMatcher(const MatcherT& matcher, ArgT* arg, const std::string& matcherCallAsString) { return expressionResultBuilderFromMatcher(matcher, matcherCallAsString) .setLhs(Catch::toString(arg)) .setResultType(matcher.match(arg)); } struct TestFailureException {}; class ScopedInfo { public: ScopedInfo() : m_resultBuilder(ResultWas::Info) { getResultCapture().pushScopedInfo(this); } ~ScopedInfo() { getResultCapture().popScopedInfo(this); } template ScopedInfo& operator << (const T& value) { m_resultBuilder << value; return *this; } AssertionResult buildResult(const AssertionInfo& assertionInfo) const { return m_resultBuilder.buildResult(assertionInfo); } private: ExpressionResultBuilder m_resultBuilder; }; // This is just here to avoid compiler warnings with macro constants and boolean literals inline bool isTrue(bool value) { return value; } } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ASSERTIONINFO_NAME INTERNAL_CATCH_UNIQUE_NAME( __assertionInfo ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ACCEPT_EXPR( evaluatedExpr, resultDisposition, originalExpr ) \ if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, INTERNAL_CATCH_ASSERTIONINFO_NAME ) ) { \ if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \ if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \ if( !Catch::shouldContinueOnFailure( resultDisposition ) ) throw Catch::TestFailureException(); \ if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \ } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ACCEPT_INFO( expr, macroName, resultDisposition ) \ Catch::AssertionInfo INTERNAL_CATCH_ASSERTIONINFO_NAME( macroName, CATCH_INTERNAL_LINEINFO, expr, resultDisposition ); /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \ try { \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionDecomposer()->*expr ).endExpression( resultDisposition ), resultDisposition, expr ); \ } catch( Catch::TestFailureException& ) { \ throw; \ } catch( ... ) { \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), \ resultDisposition | Catch::ResultDisposition::ContinueOnFailure, expr ); \ throw; \ } \ } while( Catch::isTrue( false ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( !Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \ try { \ expr; \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \ } \ catch( ... ) { \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), resultDisposition, false ); \ } \ } while( Catch::isTrue( false ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \ try { \ if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \ expr; \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::DidntThrowException ), resultDisposition, false ); \ } \ } \ catch( Catch::TestFailureException& ) { \ throw; \ } \ catch( exceptionType ) { \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \ } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( expr, exceptionType, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \ INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \ } while( Catch::isTrue( false ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \ INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \ catch( ... ) { \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \ resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \ } \ } while( Catch::isTrue( false ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( reason, resultType, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( "", macroName, resultDisposition ); \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( resultType ) << reason, resultDisposition, true ) \ } while( Catch::isTrue( false ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_SCOPED_INFO( log, macroName ) \ INTERNAL_CATCH_ACCEPT_INFO( "", macroName, Catch::ResultDisposition::Normal ); \ Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); \ INTERNAL_CATCH_UNIQUE_NAME( info ) << log /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ do { \ INTERNAL_CATCH_ACCEPT_INFO( #arg " " #matcher, macroName, resultDisposition ); \ try { \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::expressionResultBuilderFromMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), resultDisposition, false ); \ } catch( Catch::TestFailureException& ) { \ throw; \ } catch( ... ) { \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \ resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \ throw; \ } \ } while( Catch::isTrue( false ) ) // #included from: internal/catch_section.hpp #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED #include namespace Catch { class Section { public: Section(const std::string& name, const std::string& description, const SourceLineInfo& lineInfo) : m_name(name), m_sectionIncluded(getCurrentContext().getResultCapture().sectionStarted(name, description, lineInfo, m_assertions)) {} ~Section() { if (m_sectionIncluded) { getCurrentContext().getResultCapture().sectionEnded(m_name, m_assertions); } } // This indicates whether the section should be executed or not operator bool() { return m_sectionIncluded; } private: std::string m_name; Counts m_assertions; bool m_sectionIncluded; }; } // end namespace Catch #define INTERNAL_CATCH_SECTION( name, desc ) \ if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( name, desc, CATCH_INTERNAL_LINEINFO ) ) // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #include #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue(std::size_t index) const = 0; virtual std::size_t size() const = 0; }; template class BetweenGenerator : public IGenerator { public: BetweenGenerator(T from, T to) : m_from(from), m_to(to) {} virtual T getValue(std::size_t index) const { return m_from + static_cast(index); } virtual std::size_t size() const { return static_cast(1 + m_to - m_from); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { public: ValuesGenerator() {} void add(T value) { m_values.push_back(value); } virtual T getValue(std::size_t index) const { return m_values[index]; } virtual std::size_t size() const { return m_values.size(); } private: std::vector m_values; }; template class CompositeGenerator { public: CompositeGenerator() : m_totalSize(0) {} // *** Move semantics, similar to auto_ptr *** CompositeGenerator(CompositeGenerator& other) : m_fileInfo(other.m_fileInfo), m_totalSize(0) { move(other); } CompositeGenerator& setFileInfo(const char* fileInfo) { m_fileInfo = fileInfo; return *this; } ~CompositeGenerator() { deleteAll(m_composed); } operator T() const { size_t overallIndex = getCurrentContext().getGeneratorIndex(m_fileInfo, m_totalSize); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for (size_t index = 0; it != itEnd; ++it) { const IGenerator* generator = *it; if (overallIndex >= index && overallIndex < index + generator->size()) { return generator->getValue(overallIndex - index); } index += generator->size(); } CATCH_INTERNAL_ERROR("Indexed past end of generated range"); return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so } void add(const IGenerator* generator) { m_totalSize += generator->size(); m_composed.push_back(generator); } CompositeGenerator& then(CompositeGenerator& other) { move(other); return *this; } CompositeGenerator& then(T value) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add(value); add(valuesGen); return *this; } private: void move(CompositeGenerator& other) { std::copy(other.m_composed.begin(), other.m_composed.end(), std::back_inserter(m_composed)); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between(T from, T to) { CompositeGenerator generators; generators.add(new BetweenGenerator(from, to)); return generators; } template CompositeGenerator values(T val1, T val2) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add(val1); valuesGen->add(val2); generators.add(valuesGen); return generators; } template CompositeGenerator values(T val1, T val2, T val3) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add(val1); valuesGen->add(val2); valuesGen->add(val3); generators.add(valuesGen); return generators; } template CompositeGenerator values(T val1, T val2, T val3, T val4) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add(val1); valuesGen->add(val2); valuesGen->add(val3); valuesGen->add(val4); generators.add(valuesGen); return generators; } } // end namespace Generators using namespace Generators; } // end namespace Catch #define INTERNAL_CATCH_LINESTR2( line ) #line #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) // #included from: internal/catch_interfaces_exception.h #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include namespace Catch { typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate() const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator(std::string(*translateFunction)(T&)) : m_translateFunction(translateFunction) {} virtual std::string translate() const { try { throw; } catch (T& ex) { return m_translateFunction(ex); } } protected: std::string(*m_translateFunction)(T&); }; public: template ExceptionTranslatorRegistrar(std::string(*translateFunction)(T&)) { getMutableRegistryHub().registerTranslator (new ExceptionTranslator(translateFunction)); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #include #include namespace Catch { namespace Detail { class Approx { public: explicit Approx(double value) : m_epsilon(std::numeric_limits::epsilon() * 100), m_scale(1.0), m_value(value) {} Approx(const Approx& other) : m_epsilon(other.m_epsilon), m_scale(other.m_scale), m_value(other.m_value) {} static Approx custom() { return Approx(0); } Approx operator()(double value) { Approx approx(value); approx.epsilon(m_epsilon); approx.scale(m_scale); return approx; } friend bool operator == (double lhs, const Approx& rhs) { // Thanks to Richard Harris for his help refining this formula return fabs(lhs - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(fabs(lhs), fabs(rhs.m_value))); } friend bool operator == (const Approx& lhs, double rhs) { return operator==(rhs, lhs); } friend bool operator != (double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } friend bool operator != (const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } Approx& epsilon(double newEpsilon) { m_epsilon = newEpsilon; return *this; } Approx& scale(double newScale) { m_scale = newScale; return *this; } std::string toString() const { std::ostringstream oss; oss << "Approx( " << m_value << " )"; return oss.str(); } private: double m_epsilon; double m_scale; double m_value; }; } template<> inline std::string toString(const Detail::Approx& value) { return value.toString(); } } // end namespace Catch // #included from: internal/catch_matchers.hpp #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED namespace Catch { namespace Matchers { namespace Impl { template struct Matcher : SharedImpl { typedef ExpressionT ExpressionType; virtual ~Matcher() {} virtual Ptr clone() const = 0; virtual bool match(const ExpressionT& expr) const = 0; virtual std::string toString() const = 0; }; template struct MatcherImpl : Matcher { virtual Ptr > clone() const { return Ptr >(new DerivedT(static_cast(*this))); } }; namespace Generic { template class AllOf : public MatcherImpl, ExpressionT> { public: AllOf() {} AllOf(const AllOf& other) : m_matchers(other.m_matchers) {} AllOf& add(const Matcher& matcher) { m_matchers.push_back(matcher.clone()); return *this; } virtual bool match(const ExpressionT& expr) const { for (std::size_t i = 0; i < m_matchers.size(); ++i) if (!m_matchers[i]->match(expr)) { return false; } return true; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for (std::size_t i = 0; i < m_matchers.size(); ++i) { if (i != 0) { oss << " and "; } oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } private: std::vector > > m_matchers; }; template class AnyOf : public MatcherImpl, ExpressionT> { public: AnyOf() {} AnyOf(const AnyOf& other) : m_matchers(other.m_matchers) {} AnyOf& add(const Matcher& matcher) { m_matchers.push_back(matcher.clone()); return *this; } virtual bool match(const ExpressionT& expr) const { for (std::size_t i = 0; i < m_matchers.size(); ++i) if (m_matchers[i]->match(expr)) { return true; } return false; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for (std::size_t i = 0; i < m_matchers.size(); ++i) { if (i != 0) { oss << " or "; } oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } private: std::vector > > m_matchers; }; } namespace StdString { struct Equals : MatcherImpl { Equals(const std::string& str) : m_str(str) {} Equals(const Equals& other) : m_str(other.m_str) {} virtual ~Equals(); virtual bool match(const std::string& expr) const { return m_str == expr; } virtual std::string toString() const { return "equals: \"" + m_str + "\""; } std::string m_str; }; struct Contains : MatcherImpl { Contains(const std::string& substr) : m_substr(substr) {} Contains(const Contains& other) : m_substr(other.m_substr) {} virtual ~Contains(); virtual bool match(const std::string& expr) const { return expr.find(m_substr) != std::string::npos; } virtual std::string toString() const { return "contains: \"" + m_substr + "\""; } std::string m_substr; }; struct StartsWith : MatcherImpl { StartsWith(const std::string& substr) : m_substr(substr) {} StartsWith(const StartsWith& other) : m_substr(other.m_substr) {} virtual ~StartsWith(); virtual bool match(const std::string& expr) const { return expr.find(m_substr) == 0; } virtual std::string toString() const { return "starts with: \"" + m_substr + "\""; } std::string m_substr; }; struct EndsWith : MatcherImpl { EndsWith(const std::string& substr) : m_substr(substr) {} EndsWith(const EndsWith& other) : m_substr(other.m_substr) {} virtual ~EndsWith(); virtual bool match(const std::string& expr) const { return expr.find(m_substr) == expr.size() - m_substr.size(); } virtual std::string toString() const { return "ends with: \"" + m_substr + "\""; } std::string m_substr; }; } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred template inline Impl::Generic::AllOf AllOf(const Impl::Matcher& m1, const Impl::Matcher& m2) { return Impl::Generic::AllOf().add(m1).add(m2); } template inline Impl::Generic::AllOf AllOf(const Impl::Matcher& m1, const Impl::Matcher& m2, const Impl::Matcher& m3) { return Impl::Generic::AllOf().add(m1).add(m2).add(m3); } template inline Impl::Generic::AnyOf AnyOf(const Impl::Matcher& m1, const Impl::Matcher& m2) { return Impl::Generic::AnyOf().add(m1).add(m2); } template inline Impl::Generic::AnyOf AnyOf(const Impl::Matcher& m1, const Impl::Matcher& m2, const Impl::Matcher& m3) { return Impl::Generic::AnyOf().add(m1).add(m2).add(m3); } inline Impl::StdString::Equals Equals(const std::string& str) { return Impl::StdString::Equals(str); } inline Impl::StdString::Contains Contains(const std::string& substr) { return Impl::StdString::Contains(substr); } inline Impl::StdString::StartsWith StartsWith(const std::string& substr) { return Impl::StdString::StartsWith(substr); } inline Impl::StdString::EndsWith EndsWith(const std::string& substr) { return Impl::StdString::EndsWith(substr); } } // namespace Matchers using namespace Matchers; } // namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // #included from: internal/catch_interfaces_runner.h #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED #include namespace Catch { class TestCaseInfo; struct IRunner { virtual ~IRunner(); }; } #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public SharedImpl { public: OcMethod(Class cls, SEL sel) : m_cls(cls), m_sel(sel) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector(obj, @selector(setUp)); performOptionalSelector(obj, m_sel); performOptionalSelector(obj, @selector(tearDown)); arcSafeRelease(obj); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail { inline bool startsWith(const std::string& str, const std::string& sub) { return str.length() > sub.length() && str.substr(0, sub.length()) == sub; } inline std::string getAnnotation(Class cls, const std::string& annotationName, const std::string& testCaseName) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString(selStr); arcSafeRelease(selStr); id value = performOptionalSelector(cls, sel); if (value) { return [(NSString*)value UTF8String]; } return ""; } } inline size_t registerTestMethods() { size_t noTestMethods = 0; int noClasses = objc_getClassList(NULL, 0); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc(sizeof(Class) * noClasses); objc_getClassList(classes, noClasses); for (int c = 0; c < noClasses; c++) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList(cls, &count); for (u_int m = 0; m < count ; m++) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if (Detail::startsWith(methodName, "Catch_TestCase_")) { std::string testCaseName = methodName.substr(15); std::string name = Detail::getAnnotation(cls, "Name", testCaseName); std::string desc = Detail::getAnnotation(cls, "Description", testCaseName); const char* className = class_getName(cls); getMutableRegistryHub().registerTest(TestCaseInfo(new OcMethod(cls, selector), className, name.c_str(), desc.c_str(), SourceLineInfo())); noTestMethods++; } } free(methods); } } return noTestMethods; } namespace Matchers { namespace Impl { namespace NSStringMatchers { template struct StringHolder : MatcherImpl { StringHolder(NSString* substr) : m_substr([substr copy]) {} StringHolder(StringHolder const& other) : m_substr([other.m_substr copy]) {} StringHolder() { arcSafeRelease(m_substr); } NSString* m_substr; }; struct Equals : StringHolder { Equals(NSString* substr) : StringHolder(substr) {} virtual bool match(ExpressionType const& str) const { return [str isEqualToString:m_substr]; } virtual std::string toString() const { return "equals string: \"" + Catch::toString(m_substr) + "\""; } }; struct Contains : StringHolder { Contains(NSString* substr) : StringHolder(substr) {} virtual bool match(ExpressionType const& str) const { return [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string toString() const { return "contains string: \"" + Catch::toString(m_substr) + "\""; } }; struct StartsWith : StringHolder { StartsWith(NSString* substr) : StringHolder(substr) {} virtual bool match(ExpressionType const& str) const { return [str rangeOfString:m_substr].location == 0; } virtual std::string toString() const { return "starts with: \"" + Catch::toString(m_substr) + "\""; } }; struct EndsWith : StringHolder { EndsWith(NSString* substr) : StringHolder(substr) {} virtual bool match(ExpressionType const& str) const { return [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string toString() const { return "ends with: \"" + Catch::toString(m_substr) + "\""; } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals(NSString* substr) { return Impl::NSStringMatchers::Equals(substr); } inline Impl::NSStringMatchers::Contains Contains(NSString* substr) { return Impl::NSStringMatchers::Contains(substr); } inline Impl::NSStringMatchers::StartsWith StartsWith(NSString* substr) { return Impl::NSStringMatchers::StartsWith(substr); } inline Impl::NSStringMatchers::EndsWith EndsWith(NSString* substr) { return Impl::NSStringMatchers::EndsWith(substr); } } // namespace Matchers using namespace Matchers; } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_TEST_CASE( name, desc )\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\ return @ name; \ }\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) #endif #if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER ) // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED // Collect all the implementation files together here // These are the equivalent of what would usually be cpp files #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // #included from: catch_runner.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED namespace Catch { class Command { public: Command() {} explicit Command(const std::string& name) : m_name(name) { } Command& operator += (const std::string& arg) { m_args.push_back(arg); return *this; } Command& operator += (const Command& other) { std::copy(other.m_args.begin(), other.m_args.end(), std::back_inserter(m_args)); if (m_name.empty()) { m_name = other.m_name; } return *this; } Command operator + (const Command& other) { Command newCommand(*this); newCommand += other; return newCommand; } operator SafeBool::type() const { return SafeBool::makeSafe(!m_name.empty() || !m_args.empty()); } std::string name() const { return m_name; } std::string operator[](std::size_t i) const { return m_args[i]; } std::size_t argsCount() const { return m_args.size(); } CATCH_ATTRIBUTE_NORETURN void raiseError(const std::string& message) const { std::ostringstream oss; if (m_name.empty()) { oss << "Error while parsing " << m_name << ". " << message << "."; } else { oss << "Error while parsing arguments. " << message << "."; } if (m_args.size() > 0) { oss << " Arguments were:"; } for (std::size_t i = 0; i < m_args.size(); ++i) { oss << " " << m_args[i]; } throw std::domain_error(oss.str()); } private: std::string m_name; std::vector m_args; }; class CommandParser { public: CommandParser(int argc, char const * const * argv) : m_argc(static_cast(argc)), m_argv(argv) {} std::string exeName() const { return m_argv[0]; } Command find(const std::string& arg1, const std::string& arg2, const std::string& arg3) const { return find(arg1) + find(arg2) + find(arg3); } Command find(const std::string& shortArg, const std::string& longArg) const { return find(shortArg) + find(longArg); } Command find(const std::string& arg) const { if (arg.empty()) { return getArgs("", 1); } else for (std::size_t i = 1; i < m_argc; ++i) if (m_argv[i] == arg) { return getArgs(m_argv[i], i + 1); } return Command(); } Command getDefaultArgs() const { return getArgs("", 1); } private: Command getArgs(const std::string& cmdName, std::size_t from) const { Command command(cmdName); for (std::size_t i = from; i < m_argc && m_argv[i][0] != '-'; ++i) { command += m_argv[i]; } return command; } std::size_t m_argc; char const * const * m_argv; }; class OptionParser : public SharedImpl { public: OptionParser(int minArgs = 0, int maxArgs = 0) : m_minArgs(minArgs), m_maxArgs(maxArgs) {} virtual ~OptionParser() {} Command find(const CommandParser& parser) const { Command cmd; for (std::vector::const_iterator it = m_optionNames.begin(); it != m_optionNames.end(); ++it) { cmd += parser.find(*it); } return cmd; } void validateArgs(const Command& args) const { if (tooFewArgs(args) || tooManyArgs(args)) { std::ostringstream oss; if (m_maxArgs == -1) { oss << "Expected at least " << pluralise(static_cast(m_minArgs), "argument"); } else if (m_minArgs == m_maxArgs) { oss << "Expected " << pluralise(static_cast(m_minArgs), "argument"); } else { oss << "Expected between " << m_minArgs << " and " << m_maxArgs << " argument"; } args.raiseError(oss.str()); } } void parseIntoConfig(const CommandParser& parser, ConfigData& config) { if (Command cmd = find(parser)) { validateArgs(cmd); parseIntoConfig(cmd, config); } } virtual void parseIntoConfig(const Command& cmd, ConfigData& config) = 0; virtual std::string argsSynopsis() const = 0; virtual std::string optionSummary() const = 0; virtual std::string optionDescription() const { return ""; } std::string optionNames() const { std::string names; for (std::vector::const_iterator it = m_optionNames.begin(); it != m_optionNames.end(); ++it) { if (!it->empty()) { if (!names.empty()) { names += ", "; } names += *it; } else { names = "[" + names; } } if (names[0] == '[') { names += "]"; } return names; } protected: bool tooFewArgs(const Command& args) const { return args.argsCount() < static_cast(m_minArgs); } bool tooManyArgs(const Command& args) const { return m_maxArgs >= 0 && args.argsCount() > static_cast(m_maxArgs); } std::vector m_optionNames; int m_minArgs; int m_maxArgs; }; namespace Options { class HelpOptionParser : public OptionParser { public: HelpOptionParser() { m_optionNames.push_back("-?"); m_optionNames.push_back("-h"); m_optionNames.push_back("--help"); } virtual std::string argsSynopsis() const { return "[