├── .coveragerc
├── .github
└── workflows
│ └── checks.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── .readthedocs.yaml
├── .travis.yml
├── AUTHORS.rst
├── HISTORY.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── docs
├── Makefile
├── api.rst
├── conf.py
├── index.rst
└── make.bat
├── fauxfactory
├── __init__.py
├── constants.py
├── factories
│ ├── __init__.py
│ ├── booleans.py
│ ├── choices.py
│ ├── dates.py
│ ├── internet.py
│ ├── numbers.py
│ ├── strings.py
│ └── systems.py
├── facts.json
└── helpers.py
├── pyproject.toml
├── requirements-dev.lock
├── requirements.lock
├── tests
├── __init__.py
├── test_booleans.py
├── test_check_validation.py
├── test_choices.py
├── test_dates.py
├── test_datetime.py
├── test_dir.py
├── test_domain.py
├── test_emails.py
├── test_getattr.py
├── test_html.py
├── test_ipaddress.py
├── test_lorem_ipsum.py
├── test_macs.py
├── test_netmasks.py
├── test_numbers.py
├── test_strings.py
├── test_system_facts.py
├── test_system_helpers.py
├── test_time.py
├── test_urls.py
├── test_utils.py
└── test_uuids.py
└── uv.lock
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | source = fauxfactory
3 |
4 | [report]
5 | omit =
6 | */python?.?/*
7 | */site-packages/nose/*
8 |
--------------------------------------------------------------------------------
/.github/workflows/checks.yml:
--------------------------------------------------------------------------------
1 | name: Fauxfactory Checks
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | python-version: ["3.9", "3.10", "3.11", "3.12"]
16 |
17 | steps:
18 | - name: Set up Python ${{ matrix.python-version }}
19 | uses: actions/setup-python@v3
20 | with:
21 | python-version: ${{ matrix.python-version }}
22 | - uses: actions/checkout@v4
23 | - name: Install UV
24 | uses: astral-sh/setup-uv@v5
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Install dependencies
28 | run: |
29 | uv sync
30 | - name: Run checks
31 | run: |
32 | make all
33 | - name: Upload Coverage to Codecov
34 | uses: codecov/codecov-action@v1
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 |
3 | # C extensions
4 | *.so
5 |
6 | # Packages
7 | *.egg
8 | *.egg-info
9 | dist
10 | build
11 | eggs
12 | parts
13 | bin
14 | var
15 | sdist
16 | develop-eggs
17 | .installed.cfg
18 | lib
19 | lib64
20 | __pycache__
21 | MANIFEST
22 |
23 | # Installer logs
24 | pip-log.txt
25 |
26 | # Unit test / coverage reports
27 | .coverage
28 | .tox
29 | nosetests.xml
30 | coverage.xml
31 |
32 | # Translations
33 | *.mo
34 |
35 | # Mr Developer
36 | .mr.developer.cfg
37 | .project
38 | .pydevproject
39 |
40 | # Documentation artifacts
41 | /docs/_build/
42 |
43 | # Vim swap files
44 | *.swp
45 | .pytest_cache
46 | .idea
47 | pyvenv.cfg
48 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # configuration for pre-commit git hooks
2 |
3 | repos:
4 | - repo: https://github.com/pre-commit/pre-commit-hooks
5 | rev: v4.5.0
6 | hooks:
7 | - id: trailing-whitespace
8 | - id: end-of-file-fixer
9 | - id: debug-statements
10 | - repo: https://github.com/astral-sh/ruff-pre-commit
11 | # Ruff version.
12 | rev: v1.3.1
13 | hooks:
14 | # Run the linter.
15 | - id: ruff
16 | # Run the formatter.
17 | - id: ruff-format
--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------
1 | 3.12.2
2 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file for Sphinx projects
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | # Required
5 | version: 2
6 |
7 | # Set the OS, Python version and other tools you might need
8 | build:
9 | os: ubuntu-22.04
10 | tools:
11 | python: "latest"
12 | # You can also specify other tool versions:
13 | # nodejs: "20"
14 | # rust: "1.70"
15 | # golang: "1.20"
16 |
17 | # Build documentation in the "docs/" directory with Sphinx
18 | sphinx:
19 | configuration: docs/conf.py
20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
21 | # builder: "dirhtml"
22 | # Fail on all warnings to avoid broken references
23 | # fail_on_warning: true
24 |
25 | # Optionally build your docs in additional formats such as PDF and ePub
26 | formats: all
27 | # - epub
28 |
29 | # Optional but recommended, declare the Python requirements required
30 | # to build your documentation
31 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
32 | python:
33 | install:
34 | - requirements: docs/requirements.txt
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: xenial
2 | sudo: false
3 | language: python
4 | python:
5 | - 3.9
6 | - 3.10
7 | - 3.11
8 | - 3.12
9 |
10 | install:
11 | - pip install -U pip
12 | - pip install -r requirements-optional.txt
13 | script:
14 | - make all
15 | after_success:
16 | - codecov
17 | notifications:
18 | email:
19 | on_success: always
20 | on_failure: always
21 | deploy:
22 | provider: pypi
23 | skip_existing: true
24 | skip_cleanup: true
25 | # mshriver owned
26 | user: mshriver
27 | distributions: sdist bdist_wheel
28 | password:
29 | secure: "Hy941hCWVzI61chaGA1n77tNhJK7eT0ePpzZCO2i9bWzoakhlzwUTaPNupFiFSfx1ao3CXo8fpBEY9czNNGgi8rK9w5wwZrGA87mp+ugWfWgqfDhmW83MKvutGvjqLwyAXwauTRcOMdFErnO2eZuXGYPltfj4hoQCZ5jku+XZts="
30 | on:
31 | tags: true
32 | repo: omaciel/fauxfactory
33 |
--------------------------------------------------------------------------------
/AUTHORS.rst:
--------------------------------------------------------------------------------
1 | Authors
2 | =======
3 |
4 | FauxFactory is written and maintained by Og Maciel and various
5 | contributors.
6 |
7 | Development Lead
8 | ----------------
9 |
10 | - Og Maciel `@omaciel `_
11 |
12 | Contributors
13 | ------------
14 |
15 | - Corey Welton `@cswiii `_
16 | - Elyézer Rezende `@elyezer `_
17 | - Gilad Shefer `@gshefer `_
18 | - Jacob Callahan `@JacobCallahan `_
19 | - James Laska `@jlaska `_
20 | - Jefferson Fausto Vaz `@faustovaz `_
21 | - Jeremy Audet `@Ichimonji10 `_
22 | - Jonathan Edwards `@apense `_
23 | - Kedar Bidarkar `@kbidarkar `_
24 | - Pavel Zagalsky `@pavelzag `_
25 | - Renzo Nuccitelli `@renzon `_
26 | - Sachin Ghai `@sghai `_
27 | - Milan Falešník `@mfalesni `_
28 | - Nikhil Dhandre `@digitronik `_
29 | - Mike Shriver `@mshriver `_
30 | - Lisa Walker `@liwalker-rh `_
31 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | .. :changelog:
2 |
3 | Release History
4 | ===============
5 |
6 | 3.1.2 (2025-03-04)
7 | ------------------
8 |
9 | - Add option to disable random seed.
10 |
11 | 3.1.1 (2024-03-26)
12 | ------------------
13 |
14 | - Dropping support for Python 3.6, 3.7; added 3.11, 3.12.
15 | - Several code linting and smell checks.
16 | - Improve execution time of some key methods
17 | - Better selection for CJK characters.
18 |
19 | 3.1.0 (2020-11-10)
20 | ------------------
21 |
22 | - Support static analysis and type annotation
23 | - CI dropped Python 3.5
24 |
25 | 3.0.6 (2019-07-30)
26 | ------------------
27 |
28 | - Change travis deploy credentials to token
29 |
30 | 3.0.5 (2019-07-30)
31 | ------------------
32 |
33 | - Update setuptools versioning, add travis deployment
34 |
35 | 3.0.4 (2019-07-30)
36 | ------------------
37 |
38 | - Resolve flake failures in travis
39 |
40 | 3.0.3 (2019-07-30)
41 | ------------------
42 |
43 | - Fixes for warnings on file resources
44 |
45 | 3.0.2 (2018-04-10)
46 | ------------------
47 |
48 | - Really include facts.json to the package
49 |
50 | 3.0.1 (2018-04-10)
51 | ------------------
52 |
53 | - Add facts.json to manifest (2217706, @m-bucher)
54 |
55 | 3.0.0 (2018-04-10)
56 | ------------------
57 |
58 | - Make `gen_utf8` return optionally only BMP characters
59 | (6201b63)
60 | - Don't install tests into the binary distribution
61 | (b291873, @evgeni)
62 | - Use floor division operator in base_repr for Python 3
63 | compatibility (914178a, @gshefer)
64 | - New `gen_octagonal` and `gen_hexadecimal` methods added
65 | (57f5d17, @gshefer)
66 |
67 | 2.1.0 (2017-03-30)
68 | ------------------
69 |
70 | - All methods now allow you to provide a callable which will be
71 | used to filter values being returned, the number of tries, and
72 | a default value to be returned if the filter cannot match the
73 | values being generated after the number of tries. (2a7523, @renzon)
74 |
75 | 2.0.9 (2016-01-12)
76 | ------------------
77 |
78 | - Force randomness every time `random` is used to make sure
79 | that unique values are generated when running on multi-process
80 | environments, such as py.test with the pytest-xdist plugin.
81 |
82 | 2.0.8 (2015-09-18)
83 | ------------------
84 |
85 | - Updated the `gen_mac` method to allow the generation of
86 | unicast/multicast and globally/locally MAC addresses.
87 |
88 | 2.0.7 (2015-05-28)
89 | ------------------
90 |
91 | - Updated the `gen_ipaddr` method to allow the generation of IP
92 | addresses that start with a valid range prefix. (048715d, @mfalesni)
93 |
94 | 2.0.6 (2015-02-24)
95 | ------------------
96 |
97 | - Added support for **Python 2.6**.
98 | - Cleaned up the MANIFEST file.
99 |
100 | 2.0.5 (2015-02-16)
101 | ------------------
102 |
103 | - Improved the unicode letters generator to avoid returning control
104 | characters and other non-letter characters.
105 |
106 | 2.0.4 (2014-12-19)
107 | ------------------
108 |
109 | - Altered `gen_integer` to properly check for long() on Python 2.
110 |
111 | 2.0.3 (2014-12-17)
112 | ------------------
113 |
114 | - Dropped the class-wide FauxFactory deprecation warning.
115 | - Refactored the `deprecated` decorator function to comply with pylint
116 | and flake8.
117 | - Make gen_netmask verify function arguments.
118 | - Make `gen_netmask` raise a `ValueError` if `min_cidr` is less than
119 | 0 or `max_cidr` is greater than 32. Add tests for this boundary
120 | checking code.
121 | - Improvements to constants and documentation.
122 |
123 |
124 | 2.0.2 (2014-10-06)
125 | ------------------
126 |
127 | - Added new netmask random generator.
128 |
129 | 2.0.1 (2014-09-30)
130 | ------------------
131 |
132 | - Added a default length of 10 to all string generator functions.
133 | - Display deprecation warnings if ``FauxFactory`` and any of its
134 | functions are used, instructing the user to use the newer functions
135 | instead.
136 |
137 | 2.0.0 (2014-09-23)
138 | ------------------
139 |
140 | - All generators are now stand-alone functions and can be imported
141 | directly from ``fauxfactory``. For example, ``from fauxfactory
142 | import gen_date``
143 | - Renamed all generator functions to use the prefix "gen\_" instead of
144 | "generate\_". For example, ``generate_date`` is now ``gen_date``.
145 | - Backwards compatibility with version 1.x.
146 | - Polished documentation.
147 |
148 | 1.0.1 (2014-09-18)
149 | ------------------
150 |
151 | - Updated ``generate_string`` to also accept ``html`` strings.
152 |
153 | 1.0.0 (2014-09-17)
154 | ------------------
155 |
156 | - Added new method generate_html
157 | - Added new makefile
158 |
159 | 0.3.1 (2014-07-10)
160 | ------------------
161 |
162 | - Check for sys.maxunicode when generating utf8 characters.
163 |
164 | 0.3.0 (2014-06-15)
165 | ------------------
166 |
167 | - FauxFactory is now Python 3 compatible
168 | - Added new method generate_utf8
169 |
170 | 0.2.1 (2014-05-09)
171 | ------------------
172 |
173 | - Fixed issue that prevented strings longer than the full length of
174 | LOREM_IPSUM_TEXT from being generated (Github Issue #16).
175 |
176 | 0.2.0 (2014-05-08)
177 | ------------------
178 |
179 | - Added new 'Lorem Ipsum' generator.
180 | - Changed license from LGPL3+ to Apache 2.0
181 |
182 | 0.1.3 (2014-04-16)
183 | ------------------
184 |
185 | - Updated character range for CJK generator to avoid generating 'tofu'
186 | characters.
187 | - Added Contributors section to README.
188 | - New `documentation
189 | `_ (@faustovaz)
190 |
191 | **Bugfixes:**
192 |
193 | - Fixed generate_string function (@faustovaz)
194 |
195 | 0.1.2 (2014-03-19)
196 | ------------------
197 |
198 | **Bugfixes:**
199 |
200 | - Generators for ``email``, ``url`` and ``IP`` should return a unicode
201 | string.
202 |
203 | 0.1.1 (2014-03-17)
204 | ------------------
205 |
206 | - Fixed formatting of README for better display on Pypi.
207 |
208 | 0.1.0 (2014-03-17)
209 | ------------------
210 |
211 | - Initial Release.
212 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2014 Og Maciel
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include AUTHORS.rst
2 | include HISTORY.rst
3 | include LICENSE
4 | include README.rst
5 | include fauxfactory/facts.json
6 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | help:
2 | @echo "Please use \`make ' where is one of:"
3 | @echo " docs-clean Remove documentation."
4 | @echo " docs-doctest Check code samples in the documentation."
5 | @echo " docs-html Compile documentation to HTML."
6 | @echo " format Run format8."
7 | @echo " lint Run format8 and pylint."
8 | @echo " test Run unit tests."
9 | @echo " test-all Run unit tests and doctests, measure coverage."
10 |
11 | all: clean lint test-all check clean docs-clean docs-html
12 |
13 | # Linting and formatting
14 | check:
15 | uvx ruff check .
16 |
17 | # Clean build artifacts
18 | clean:
19 | rm -rf build/
20 | rm -rf dist/
21 | rm -rf *.egg-info
22 | find . -type d -name __pycache__ -exec rm -rf {} +
23 | find . -type f -name "*.pyc" -delete
24 | find . -type f -name "*.pyo" -delete
25 | find . -type f -name "*.pyd" -delete
26 |
27 | docs-clean:
28 | cd docs && rm -rf _build/*
29 |
30 | docs-doctest: install-docs
31 | uv run --with '.[docs]' sphinx-build -b doctest -d docs/_build/doctrees docs/ docs/_build/doctest
32 |
33 | docs-html: install-docs
34 | uv run --with '.[docs]' sphinx-build -b html -d docs/_build/doctrees docs/ docs/_build/html
35 |
36 | format:
37 | uvx ruff format .
38 |
39 | lint: check format
40 |
41 | install-dev:
42 | uv pip install -e ".[dev]"
43 |
44 | install-docs:
45 | uv pip install -e ".[docs]"
46 |
47 | build: clean
48 | uv build
49 |
50 |
51 | publish:
52 | uv publish
53 |
54 | test: install-dev
55 | uv run --with '.[dev]' pytest -v
56 |
57 | test-all: install-dev
58 | uv run --with pytest-cov --with '.[dev]' pytest --cov-report term-missing --cov=fauxfactory
59 |
60 | .PHONY: help build check clean docs-clean docs-doctest docs-html format lint build publish test test-all
61 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | FauxFactory
2 | ===========
3 |
4 | .. image:: https://travis-ci.org/omaciel/fauxfactory.png?branch=master
5 | :target: https://travis-ci.org/omaciel/fauxfactory
6 | :alt: Build Status
7 |
8 | .. image:: https://img.shields.io/pypi/pyversions/fauxfactory.svg
9 | :target: https://pypi.python.org/pypi/fauxfactory
10 | :alt: Python Compatibility
11 |
12 | .. image:: https://badge.fury.io/py/fauxfactory.png
13 | :target: http://badge.fury.io/py/fauxfactory
14 | :alt: Current Version
15 |
16 | .. image:: https://img.shields.io/pypi/dm/fauxfactory.svg
17 | :target: https://crate.io/packages/fauxfactory/
18 | :alt: Download Statistics
19 |
20 | .. image:: https://coveralls.io/repos/omaciel/fauxfactory/badge.png?branch=master
21 | :target: https://coveralls.io/r/omaciel/fauxfactory?branch=master
22 | :alt: Test Coverage
23 |
24 | .. image:: https://img.shields.io/pypi/l/fauxfactory.svg
25 | :target: https://pypi.python.org/pypi/fauxfactory/
26 | :alt: License
27 |
28 | **FauxFactory** generates random data for your automated tests easily!
29 |
30 | There are times when you're writing tests for your application when you need to
31 | pass random, non-specific data to the areas you are testing. For these scenarios
32 | when all you need is a random string, numbers, dates, times, email address, IP,
33 | etc, then FauxFactory can help!
34 |
35 | The `full documentation
36 | `_ is available on
37 | ReadTheDocs. It can also be generated locally::
38 |
39 | pip install -r requirements-optional.txt
40 | make docs-html
41 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " devhelp to make HTML files and a Devhelp project"
34 | @echo " epub to make an epub"
35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 | @echo " text to make text files"
39 | @echo " man to make manual pages"
40 | @echo " texinfo to make Texinfo files"
41 | @echo " info to make Texinfo files and run them through makeinfo"
42 | @echo " gettext to make PO message catalogs"
43 | @echo " changes to make an overview of all changed/added/deprecated items"
44 | @echo " xml to make Docutils-native XML files"
45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 | @echo " linkcheck to check all external links for integrity"
47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 |
49 | clean:
50 | rm -rf $(BUILDDIR)/*
51 |
52 | html:
53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54 | @echo
55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56 |
57 | dirhtml:
58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59 | @echo
60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61 |
62 | singlehtml:
63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64 | @echo
65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66 |
67 | pickle:
68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69 | @echo
70 | @echo "Build finished; now you can process the pickle files."
71 |
72 | json:
73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74 | @echo
75 | @echo "Build finished; now you can process the JSON files."
76 |
77 | htmlhelp:
78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79 | @echo
80 | @echo "Build finished; now you can run HTML Help Workshop with the" \
81 | ".hhp project file in $(BUILDDIR)/htmlhelp."
82 |
83 | qthelp:
84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85 | @echo
86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FauxFactory.qhcp"
89 | @echo "To view the help file:"
90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FauxFactory.qhc"
91 |
92 | devhelp:
93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94 | @echo
95 | @echo "Build finished."
96 | @echo "To view the help file:"
97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/FauxFactory"
98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FauxFactory"
99 | @echo "# devhelp"
100 |
101 | epub:
102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103 | @echo
104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105 |
106 | latex:
107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108 | @echo
109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
111 | "(use \`make latexpdf' here to do that automatically)."
112 |
113 | latexpdf:
114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115 | @echo "Running LaTeX files through pdflatex..."
116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118 |
119 | latexpdfja:
120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121 | @echo "Running LaTeX files through platex and dvipdfmx..."
122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124 |
125 | text:
126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127 | @echo
128 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
129 |
130 | man:
131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132 | @echo
133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134 |
135 | texinfo:
136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137 | @echo
138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139 | @echo "Run \`make' in that directory to run these through makeinfo" \
140 | "(use \`make info' here to do that automatically)."
141 |
142 | info:
143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144 | @echo "Running Texinfo files through makeinfo..."
145 | make -C $(BUILDDIR)/texinfo info
146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147 |
148 | gettext:
149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150 | @echo
151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152 |
153 | changes:
154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155 | @echo
156 | @echo "The overview file is in $(BUILDDIR)/changes."
157 |
158 | linkcheck:
159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160 | @echo
161 | @echo "Link check complete; look for any errors in the above output " \
162 | "or in $(BUILDDIR)/linkcheck/output.txt."
163 |
164 | doctest:
165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166 | @echo "Testing of doctests in the sources finished, look at the " \
167 | "results in $(BUILDDIR)/doctest/output.txt."
168 |
169 | xml:
170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
171 | @echo
172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
173 |
174 | pseudoxml:
175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
176 | @echo
177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
178 |
--------------------------------------------------------------------------------
/docs/api.rst:
--------------------------------------------------------------------------------
1 | API Documentation
2 | =================
3 |
4 | This is a complete list of available methods, along with details about them.
5 |
6 | :mod:`fauxfactory`
7 | ------------------
8 |
9 | .. automodule:: fauxfactory
10 |
11 | :mod:`fauxfactory.factories.booleans`
12 | -------------------------------------
13 |
14 | .. automodule:: fauxfactory.factories.booleans
15 | :members:
16 |
17 | :mod:`fauxfactory.factories.choices`
18 | ------------------------------------
19 |
20 | .. automodule:: fauxfactory.factories.choices
21 | :members:
22 |
23 | :mod:`fauxfactory.constants`
24 | ----------------------------
25 |
26 | .. automodule:: fauxfactory.constants
27 | :members:
28 |
29 | :mod:`fauxfactory.factories.dates`
30 | ----------------------------------
31 |
32 | .. automodule:: fauxfactory.factories.dates
33 | :members:
34 |
35 | :mod:`fauxfactory.helpers`
36 | --------------------------
37 |
38 | .. automodule:: fauxfactory.helpers
39 | :members:
40 |
41 | :mod:`fauxfactory.factories.internet`
42 | -------------------------------------
43 |
44 | .. automodule:: fauxfactory.factories.internet
45 | :members:
46 |
47 | :mod:`fauxfactory.factories.numbers`
48 | ------------------------------------
49 |
50 | .. automodule:: fauxfactory.factories.numbers
51 | :members:
52 |
53 | :mod:`fauxfactory.factories.strings`
54 | ------------------------------------
55 |
56 | .. automodule:: fauxfactory.factories.strings
57 | :members:
58 |
59 | :mod:`fauxfactory.factories.systems`
60 | ------------------------------------
61 |
62 | .. automodule:: fauxfactory.factories.systems
63 | :members:
64 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """Sphinx documentation generator configuration file.
3 |
4 | The full set of configuration options is listed on the Sphinx website:
5 | http://sphinx-doc.org/config.html
6 |
7 | """
8 | # FauxFactory documentation build configuration file, created by
9 | # sphinx-quickstart on Wed Apr 16 15:46:04 2014.
10 | #
11 | # This file is execfile()d with the current directory set to its
12 | # containing dir.
13 | #
14 | # Note that not all possible configuration values are present in this
15 | # autogenerated file.
16 | #
17 | # All configuration values have a default; values that are commented out
18 | # serve to show the default.
19 |
20 | import os
21 | import sys
22 |
23 | # pylint:disable=invalid-name
24 |
25 | # If extensions (or modules to document with autodoc) are in another directory,
26 | # add these directories to sys.path here. If the directory is relative to the
27 | # documentation root, use os.path.abspath to make it absolute, like shown here.
28 | sys.path.insert(
29 | 0, os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.pardir))
30 | )
31 |
32 | # -- General configuration ------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | # needs_sphinx = '1.0'
36 |
37 | # Add any Sphinx extension module names here, as strings. They can be
38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
39 | # ones.
40 | extensions = [
41 | "sphinx.ext.autodoc",
42 | "sphinx.ext.doctest",
43 | "sphinx.ext.viewcode",
44 | ]
45 |
46 | # Add any paths that contain templates here, relative to this directory.
47 | templates_path = ["_templates"]
48 |
49 | # The suffix of source filenames.
50 | source_suffix = ".rst"
51 |
52 | # The encoding of source files.
53 | # source_encoding = 'utf-8-sig'
54 |
55 | # The master toctree document.
56 | master_doc = "index"
57 |
58 | # General information about the project.
59 | project = "FauxFactory"
60 | copyright = "2014-2025, Og Maciel" # pylint:disable=redefined-builtin
61 |
62 | # The version info for the project you're documenting, acts as replacement for
63 | # |version| and |release|, also used in various other places throughout the
64 | # built documents.
65 | #
66 | # The short X.Y version.
67 | version = "3.1"
68 | # The full version, including alpha/beta/rc tags.
69 | release = "3.1.2"
70 |
71 | # The language for content autogenerated by Sphinx. Refer to documentation
72 | # for a list of supported languages.
73 | # language = None
74 |
75 | # There are two options for replacing |today|: either, you set today to some
76 | # non-false value, then it is used:
77 | # today = ''
78 | # Else, today_fmt is used as the format for a strftime call.
79 | # today_fmt = '%B %d, %Y'
80 |
81 | # List of patterns, relative to source directory, that match files and
82 | # directories to ignore when looking for source files.
83 | exclude_patterns = ["_build"]
84 |
85 | # The reST default role (used for this markup: `text`) to use for all
86 | # documents.
87 | # default_role = None
88 |
89 | # If true, '()' will be appended to :func: etc. cross-reference text.
90 | # add_function_parentheses = True
91 |
92 | # If true, the current module name will be prepended to all description
93 | # unit titles (such as .. function::).
94 | # add_module_names = True
95 |
96 | # If true, sectionauthor and moduleauthor directives will be shown in the
97 | # output. They are ignored by default.
98 | # show_authors = False
99 |
100 | # The name of the Pygments (syntax highlighting) style to use.
101 | pygments_style = "sphinx"
102 |
103 | # A list of ignored prefixes for module index sorting.
104 | # modindex_common_prefix = []
105 |
106 | # If true, keep warnings as "system message" paragraphs in the built documents.
107 | # keep_warnings = False
108 |
109 | # If true, Sphinx will warn about all references where the target cannot be
110 | # found.
111 | nitpicky = True
112 |
113 | # A list of (type, target) tuples (by default empty) that should be ignored
114 | # when generating warnings in “nitpicky mode”.
115 | nitpick_ignore = [
116 | ("py:class", "bool"),
117 | ("py:class", "dict"),
118 | ("py:class", "int"),
119 | ("py:class", "list"),
120 | ("py:class", "str"),
121 | ("py:class", "tuple"),
122 | ]
123 |
124 |
125 | # -- Options for HTML output ----------------------------------------------
126 |
127 | # The theme to use for HTML and HTML Help pages. See the documentation for
128 | # a list of builtin themes.
129 | html_theme = "nature"
130 |
131 | # Theme options are theme-specific and customize the look and feel of a theme
132 | # further. For a list of options available for each theme, see the
133 | # documentation.
134 | # html_theme_options = {}
135 |
136 | # Add any paths that contain custom themes here, relative to this directory.
137 | # html_theme_path = []
138 |
139 | # The name for this set of Sphinx documents. If None, it defaults to
140 | # " v documentation".
141 | # html_title = None
142 |
143 | # A shorter title for the navigation bar. Default is the same as html_title.
144 | # html_short_title = None
145 |
146 | # The name of an image file (relative to this directory) to place at the top
147 | # of the sidebar.
148 | # html_logo = None
149 |
150 | # The name of an image file (within the static path) to use as favicon of the
151 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
152 | # pixels large.
153 | # html_favicon = None
154 |
155 | # Add any paths that contain custom static files (such as style sheets) here,
156 | # relative to this directory. They are copied after the builtin static files,
157 | # so a file named "default.css" will overwrite the builtin "default.css".
158 | # html_static_path = ['_static']
159 |
160 | # Add any extra paths that contain custom files (such as robots.txt or
161 | # .htaccess) here, relative to this directory. These files are copied
162 | # directly to the root of the documentation.
163 | # html_extra_path = []
164 |
165 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
166 | # using the given strftime format.
167 | # html_last_updated_fmt = '%b %d, %Y'
168 |
169 | # If true, SmartyPants will be used to convert quotes and dashes to
170 | # typographically correct entities.
171 | # html_use_smartypants = True
172 |
173 | # Custom sidebar templates, maps document names to template names.
174 | # html_sidebars = {}
175 |
176 | # Additional templates that should be rendered to pages, maps page names to
177 | # template names.
178 | # html_additional_pages = {}
179 |
180 | # If false, no module index is generated.
181 | # html_domain_indices = True
182 |
183 | # If false, no index is generated.
184 | # html_use_index = True
185 |
186 | # If true, the index is split into individual pages for each letter.
187 | # html_split_index = False
188 |
189 | # If true, links to the reST sources are added to the pages.
190 | # html_show_sourcelink = True
191 |
192 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
193 | # html_show_sphinx = True
194 |
195 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
196 | # html_show_copyright = True
197 |
198 | # If true, an OpenSearch description file will be output, and all pages will
199 | # contain a tag referring to it. The value of this option must be the
200 | # base URL from which the finished HTML is served.
201 | # html_use_opensearch = ''
202 |
203 | # This is the file name suffix for HTML files (e.g. ".xhtml").
204 | # html_file_suffix = None
205 |
206 | # Output file base name for HTML help builder.
207 | htmlhelp_basename = "FauxFactorydoc"
208 |
209 |
210 | # -- Options for LaTeX output ---------------------------------------------
211 |
212 | latex_elements = {
213 | # The paper size ('letterpaper' or 'a4paper').
214 | # 'papersize': 'letterpaper',
215 | # The font size ('10pt', '11pt' or '12pt').
216 | # 'pointsize': '10pt',
217 | # Additional stuff for the LaTeX preamble.
218 | # 'preamble': '',
219 | }
220 |
221 | # Grouping the document tree into LaTeX files. List of tuples
222 | # (source start file, target name, title,
223 | # author, documentclass [howto, manual, or own class]).
224 | latex_documents = [
225 | ("index", "FauxFactory.tex", "FauxFactory Documentation", "Og Maciel", "manual")
226 | ]
227 |
228 | # The name of an image file (relative to this directory) to place at the top of
229 | # the title page.
230 | # latex_logo = None
231 |
232 | # For "manual" documents, if this is true, then toplevel headings are parts,
233 | # not chapters.
234 | # latex_use_parts = False
235 |
236 | # If true, show page references after internal links.
237 | # latex_show_pagerefs = False
238 |
239 | # If true, show URL addresses after external links.
240 | # latex_show_urls = False
241 |
242 | # Documents to append as an appendix to all manuals.
243 | # latex_appendices = []
244 |
245 | # If false, no module index is generated.
246 | # latex_domain_indices = True
247 |
248 |
249 | # -- Options for manual page output ---------------------------------------
250 |
251 | # One entry per manual page. List of tuples
252 | # (source start file, name, description, authors, manual section).
253 | man_pages = [("index", "fauxfactory", "FauxFactory Documentation", ["Og Maciel"], 1)]
254 |
255 | # If true, show URL addresses after external links.
256 | # man_show_urls = False
257 |
258 |
259 | # -- Options for Texinfo output -------------------------------------------
260 |
261 | # Grouping the document tree into Texinfo files. List of tuples
262 | # (source start file, target name, title, author,
263 | # dir menu entry, description, category)
264 | texinfo_documents = [
265 | (
266 | "index",
267 | "FauxFactory",
268 | "FauxFactory Documentation",
269 | "Og Maciel",
270 | "FauxFactory",
271 | "FauxFactory generates random data for your automated tests easily!",
272 | "Miscellaneous",
273 | )
274 | ]
275 |
276 | # Documents to append as an appendix to all manuals.
277 | # texinfo_appendices = []
278 |
279 | # If false, no module index is generated.
280 | # texinfo_domain_indices = True
281 |
282 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
283 | # texinfo_show_urls = 'footnote'
284 |
285 | # If true, do not generate a @detailmenu in the "Top" node's menu.
286 | # texinfo_no_detailmenu = False
287 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | FauxFactory
2 | ===========
3 |
4 | **FauxFactory** generates random data for your automated tests easily!
5 |
6 | There are times when you're writing tests for your application when you need to
7 | pass random, non-specific data to the areas you are testing. For these scenarios
8 | when all you need is a random string, numbers, dates, times, email address, IP,
9 | etc, then FauxFactory can help!
10 |
11 | Installation
12 | ------------
13 |
14 | FauxFactory is available in PyPi and can be installed using pip::
15 |
16 | $ pip install fauxfactory
17 |
18 | You can install FauxFactory by downloading the latest version of the source
19 | code::
20 |
21 | $ git clone git@github.com:omaciel/fauxfactory.git
22 | $ cd fauxfactory
23 | $ python setup.py build install
24 |
25 | Usage
26 | -----
27 |
28 | .. testsetup::
29 |
30 | import os
31 | import sys
32 | ROOT_PATH = os.path.abspath(os.path.pardir)
33 | if ROOT_PATH not in sys.path:
34 | sys.path.append(ROOT_PATH)
35 | import fauxfactory
36 |
37 | Need a 15 character string for one of your tests?
38 |
39 | .. doctest::
40 |
41 | >>> string = fauxfactory.gen_string('alphanumeric', 15)
42 | >>> string.isalnum()
43 | True
44 | >>> len(string)
45 | 15
46 |
47 | Need a 5 character numeric string?
48 |
49 | .. doctest::
50 |
51 | >>> string = fauxfactory.gen_string('numeric', 5)
52 | >>> string.isnumeric()
53 | True
54 | >>> len(string)
55 | 5
56 |
57 | Now, let's say you need a random date:
58 |
59 | .. doctest::
60 |
61 | >>> import datetime
62 | >>> isinstance(fauxfactory.gen_date(), datetime.date)
63 | True
64 | >>> isinstance(fauxfactory.gen_datetime(), datetime.datetime)
65 | True
66 |
67 | Or a fake email with your company domain:
68 |
69 | .. doctest::
70 |
71 | >>> email = fauxfactory.gen_email(domain='mycompany')
72 | >>> '@mycompany' in email
73 | True
74 |
75 | Simple, right?
76 |
77 | Validation
78 | ----------
79 |
80 | All string functions allow validation of inputs using 3 parameters:
81 |
82 | #. validator: a callable or str with regex returning boolean signaling if
83 | random data is valid or not.
84 | #. tries: maximum number of times random data will be generated after
85 | failing validation. If the limit is reached "default" parameter will be
86 | returned.
87 | #. default: value to be returned if validation fails a "tries" number of times.
88 |
89 |
90 | Example using callable:
91 |
92 | .. doctest::
93 |
94 | >>> def start_a(value):
95 | ... return value[0] == 'a'
96 | >>> email = fauxfactory.gen_email(validator=start_a, default = 'a@b.c')
97 | >>> email[0] == 'a'
98 | True
99 |
100 |
101 | Example using regex:
102 |
103 | .. doctest::
104 |
105 | >>> n = fauxfactory.gen_string(
106 | ... 'numeric', validator='[^0].*', default = '2')
107 | >>> n != '0'
108 | True
109 |
110 | Example using tries and default:
111 |
112 | .. doctest::
113 |
114 | >>> def always_false(value):
115 | ... print('Executed')
116 | ... return False
117 | >>> fauxfactory.gen_alpha(
118 | ... validator=always_false, default = 'default value', tries=1)
119 | Executed
120 | 'default value'
121 | >>> fauxfactory.gen_alpha(
122 | ... validator=always_false, default = 'default value 2', tries=3)
123 | Executed
124 | Executed
125 | Executed
126 | 'default value 2'
127 |
128 | API
129 | ---
130 |
131 | For a full list of available methods, see the :doc:`API documentation <./api>`.
132 |
133 | .. toctree::
134 | :hidden:
135 |
136 | api
137 |
138 | Contribute
139 | ----------
140 |
141 | #. Fork `the repository`_ on GitHub and make some changes. Make sure to add
142 | yourself to `AUTHORS`_.
143 | #. Install the development requirements. ``pip install -r
144 | requirements-optional.txt``.
145 | #. Test your changes.
146 |
147 | #. Run ``make test-all`` and make sure nothing has broken.
148 | #. Run ``coverage report --show-missing`` to check for untested code.
149 | #. Add tests to the ``tests/`` directory if appropriate.
150 |
151 | Repeat this cycle as needed.
152 |
153 | #. Send a pull request and bug the maintainer until it gets merged and
154 | published. :)
155 |
156 | .. _`the repository`: http://github.com/omaciel/fauxfactory
157 | .. _`AUTHORS`: https://github.com/omaciel/fauxfactory/blob/master/AUTHORS.rst
158 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | if "%SPHINXBUILD%" == "" (
6 | set SPHINXBUILD=sphinx-build
7 | )
8 | set BUILDDIR=build
9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
10 | set I18NSPHINXOPTS=%SPHINXOPTS% source
11 | if NOT "%PAPER%" == "" (
12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
14 | )
15 |
16 | if "%1" == "" goto help
17 |
18 | if "%1" == "help" (
19 | :help
20 | echo.Please use `make ^` where ^ is one of
21 | echo. html to make standalone HTML files
22 | echo. dirhtml to make HTML files named index.html in directories
23 | echo. singlehtml to make a single large HTML file
24 | echo. pickle to make pickle files
25 | echo. json to make JSON files
26 | echo. htmlhelp to make HTML files and a HTML help project
27 | echo. qthelp to make HTML files and a qthelp project
28 | echo. devhelp to make HTML files and a Devhelp project
29 | echo. epub to make an epub
30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 | echo. text to make text files
32 | echo. man to make manual pages
33 | echo. texinfo to make Texinfo files
34 | echo. gettext to make PO message catalogs
35 | echo. changes to make an overview over all changed/added/deprecated items
36 | echo. xml to make Docutils-native XML files
37 | echo. pseudoxml to make pseudoxml-XML files for display purposes
38 | echo. linkcheck to check all external links for integrity
39 | echo. doctest to run all doctests embedded in the documentation if enabled
40 | goto end
41 | )
42 |
43 | if "%1" == "clean" (
44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
45 | del /q /s %BUILDDIR%\*
46 | goto end
47 | )
48 |
49 |
50 | %SPHINXBUILD% 2> nul
51 | if errorlevel 9009 (
52 | echo.
53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
54 | echo.installed, then set the SPHINXBUILD environment variable to point
55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
56 | echo.may add the Sphinx directory to PATH.
57 | echo.
58 | echo.If you don't have Sphinx installed, grab it from
59 | echo.http://sphinx-doc.org/
60 | exit /b 1
61 | )
62 |
63 | if "%1" == "html" (
64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
65 | if errorlevel 1 exit /b 1
66 | echo.
67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
68 | goto end
69 | )
70 |
71 | if "%1" == "dirhtml" (
72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
73 | if errorlevel 1 exit /b 1
74 | echo.
75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
76 | goto end
77 | )
78 |
79 | if "%1" == "singlehtml" (
80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
81 | if errorlevel 1 exit /b 1
82 | echo.
83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
84 | goto end
85 | )
86 |
87 | if "%1" == "pickle" (
88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
89 | if errorlevel 1 exit /b 1
90 | echo.
91 | echo.Build finished; now you can process the pickle files.
92 | goto end
93 | )
94 |
95 | if "%1" == "json" (
96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
97 | if errorlevel 1 exit /b 1
98 | echo.
99 | echo.Build finished; now you can process the JSON files.
100 | goto end
101 | )
102 |
103 | if "%1" == "htmlhelp" (
104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
105 | if errorlevel 1 exit /b 1
106 | echo.
107 | echo.Build finished; now you can run HTML Help Workshop with the ^
108 | .hhp project file in %BUILDDIR%/htmlhelp.
109 | goto end
110 | )
111 |
112 | if "%1" == "qthelp" (
113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
114 | if errorlevel 1 exit /b 1
115 | echo.
116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
117 | .qhcp project file in %BUILDDIR%/qthelp, like this:
118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\FauxFactory.qhcp
119 | echo.To view the help file:
120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\FauxFactory.ghc
121 | goto end
122 | )
123 |
124 | if "%1" == "devhelp" (
125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
126 | if errorlevel 1 exit /b 1
127 | echo.
128 | echo.Build finished.
129 | goto end
130 | )
131 |
132 | if "%1" == "epub" (
133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
134 | if errorlevel 1 exit /b 1
135 | echo.
136 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
137 | goto end
138 | )
139 |
140 | if "%1" == "latex" (
141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
142 | if errorlevel 1 exit /b 1
143 | echo.
144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
145 | goto end
146 | )
147 |
148 | if "%1" == "latexpdf" (
149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
150 | cd %BUILDDIR%/latex
151 | make all-pdf
152 | cd %BUILDDIR%/..
153 | echo.
154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
155 | goto end
156 | )
157 |
158 | if "%1" == "latexpdfja" (
159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
160 | cd %BUILDDIR%/latex
161 | make all-pdf-ja
162 | cd %BUILDDIR%/..
163 | echo.
164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
165 | goto end
166 | )
167 |
168 | if "%1" == "text" (
169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
170 | if errorlevel 1 exit /b 1
171 | echo.
172 | echo.Build finished. The text files are in %BUILDDIR%/text.
173 | goto end
174 | )
175 |
176 | if "%1" == "man" (
177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
178 | if errorlevel 1 exit /b 1
179 | echo.
180 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
181 | goto end
182 | )
183 |
184 | if "%1" == "texinfo" (
185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
186 | if errorlevel 1 exit /b 1
187 | echo.
188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
189 | goto end
190 | )
191 |
192 | if "%1" == "gettext" (
193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
194 | if errorlevel 1 exit /b 1
195 | echo.
196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
197 | goto end
198 | )
199 |
200 | if "%1" == "changes" (
201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
202 | if errorlevel 1 exit /b 1
203 | echo.
204 | echo.The overview file is in %BUILDDIR%/changes.
205 | goto end
206 | )
207 |
208 | if "%1" == "linkcheck" (
209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
210 | if errorlevel 1 exit /b 1
211 | echo.
212 | echo.Link check complete; look for any errors in the above output ^
213 | or in %BUILDDIR%/linkcheck/output.txt.
214 | goto end
215 | )
216 |
217 | if "%1" == "doctest" (
218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
219 | if errorlevel 1 exit /b 1
220 | echo.
221 | echo.Testing of doctests in the sources finished, look at the ^
222 | results in %BUILDDIR%/doctest/output.txt.
223 | goto end
224 | )
225 |
226 | if "%1" == "xml" (
227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
228 | if errorlevel 1 exit /b 1
229 | echo.
230 | echo.Build finished. The XML files are in %BUILDDIR%/xml.
231 | goto end
232 | )
233 |
234 | if "%1" == "pseudoxml" (
235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
236 | if errorlevel 1 exit /b 1
237 | echo.
238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
239 | goto end
240 | )
241 |
242 | :end
243 |
--------------------------------------------------------------------------------
/fauxfactory/__init__.py:
--------------------------------------------------------------------------------
1 | """Generate random data for your tests."""
2 |
3 | # Note flake8 do not like star imports. It makes tracking down the file/module
4 | # containg the symbol much harder than with explicit imports. This is an issue
5 | # especially for a human reader. As symbols in this file were always taken from
6 | # submodules dynamically this problem was there before introducing the start
7 | # imports. Star imports seem to not be a problem for (perhaps) smarter tools
8 | # like PyCharm and using them improves the analysis and navigation trough
9 | # the code.
10 |
11 | from fauxfactory.factories.booleans import * # noqa: F401, F403
12 | from fauxfactory.factories.choices import * # noqa: F401, F403
13 | from fauxfactory.factories.dates import * # noqa: F401, F403
14 | from fauxfactory.factories.internet import * # noqa: F401, F403
15 | from fauxfactory.factories.numbers import * # noqa: F401, F403
16 | from fauxfactory.factories.strings import * # noqa: F401, F403
17 | from fauxfactory.factories.systems import * # noqa: F401, F403
18 |
19 | __factories = {name: obj for name, obj in locals().items() if name.startswith("gen_")}
20 |
21 | # Add all method names to __all__
22 | __all__ = tuple(__factories.keys())
23 |
24 |
25 | def __dir__():
26 | return __all__
27 |
28 |
29 | def __getattr__(name):
30 | if name in __factories:
31 | return __factories[name]
32 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
33 |
--------------------------------------------------------------------------------
/fauxfactory/constants.py:
--------------------------------------------------------------------------------
1 | """Constants used by :mod:`fauxfactory`.
2 |
3 | .. data:: VALID_NETMASKS
4 |
5 | A tuple of netmasks. The tuple index corresponds to a CIDR value. For
6 | example, a CIDR of "/1" corresponds to `VALID_NETMASKS[1]`.
7 |
8 | """
9 |
10 | # The above constant descriptions can be found by Sphinx and via help().
11 | import datetime
12 | import json
13 | import os
14 | import string
15 |
16 | VALID_DIGITS = string.digits + string.ascii_letters
17 |
18 | FACTS_JSON_FILE = os.path.join(os.path.dirname(__file__), "facts.json")
19 | with open(FACTS_JSON_FILE, encoding="utf-8") as data:
20 | FACTS_JSON = json.load(data)
21 |
22 | LOREM_IPSUM_TEXT = (
23 | "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
24 | "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad "
25 | "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip "
26 | "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in "
27 | "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur "
28 | "sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
29 | "mollit anim id est laborum."
30 | )
31 |
32 | MIN_YEARS = datetime.MINYEAR
33 | MAX_YEARS = 1000 # 1000 years into the future
34 |
35 | SCHEMES = (
36 | "http",
37 | "https",
38 | "ftp",
39 | )
40 |
41 | SUBDOMAINS = (
42 | "example",
43 | "test",
44 | )
45 |
46 | TLDS = (
47 | "biz",
48 | "com",
49 | "edu",
50 | "gov",
51 | "info",
52 | "org",
53 | )
54 |
55 | VALID_NETMASKS = (
56 | "0.0.0.0",
57 | "128.0.0.0",
58 | "192.0.0.0",
59 | "224.0.0.0",
60 | "240.0.0.0",
61 | "248.0.0.0",
62 | "252.0.0.0",
63 | "254.0.0.0",
64 | "255.0.0.0",
65 | "255.128.0.0",
66 | "255.192.0.0",
67 | "255.224.0.0",
68 | "255.240.0.0",
69 | "255.248.0.0",
70 | "255.252.0.0",
71 | "255.254.0.0",
72 | "255.255.0.0",
73 | "255.255.128.0",
74 | "255.255.192.0",
75 | "255.255.224.0",
76 | "255.255.240.0",
77 | "255.255.248.0",
78 | "255.255.252.0",
79 | "255.255.254.0",
80 | "255.255.255.0",
81 | "255.255.255.128",
82 | "255.255.255.192",
83 | "255.255.255.224",
84 | "255.255.255.240",
85 | "255.255.255.248",
86 | "255.255.255.252",
87 | "255.255.255.254",
88 | "255.255.255.255",
89 | )
90 |
91 | HTML_TAGS = (
92 | "a",
93 | "abbr",
94 | "acronym",
95 | "address",
96 | "applet",
97 | "area",
98 | "b",
99 | "base",
100 | "basefont",
101 | "bdo",
102 | "big",
103 | "blink",
104 | "blockquote",
105 | "body",
106 | "br",
107 | "button",
108 | "caption",
109 | "center",
110 | "cite",
111 | "code",
112 | "col",
113 | "colgroup",
114 | "dd",
115 | "del",
116 | "dfn",
117 | "dir",
118 | "div",
119 | "dl",
120 | "dt",
121 | "em",
122 | "fieldset",
123 | "font",
124 | "form",
125 | "frame",
126 | "frameset",
127 | "h1",
128 | "h2",
129 | "h3",
130 | "h4",
131 | "h5",
132 | "h6",
133 | "head",
134 | "hr",
135 | "html",
136 | "i",
137 | "iframe",
138 | "img",
139 | "input",
140 | "ins",
141 | "isindex",
142 | "kbd",
143 | "label",
144 | "legend",
145 | "li",
146 | "link",
147 | "map",
148 | "menu",
149 | "meta",
150 | "noframes",
151 | "noscript",
152 | "object",
153 | "ol",
154 | "optgroup",
155 | "option",
156 | "p",
157 | "param",
158 | "pre",
159 | "q",
160 | "s",
161 | "samp",
162 | "script",
163 | "select",
164 | "small",
165 | "span",
166 | "strike",
167 | "strong",
168 | "style",
169 | "sub",
170 | "sup",
171 | "table",
172 | "tbody",
173 | "td",
174 | "textarea",
175 | "tfoot",
176 | "th",
177 | "thead",
178 | "title",
179 | "tr",
180 | "tt",
181 | "u",
182 | "ul",
183 | "var",
184 | )
185 |
--------------------------------------------------------------------------------
/fauxfactory/factories/__init__.py:
--------------------------------------------------------------------------------
1 | """Store all modules that generate data here."""
2 |
3 | import os
4 | import random
5 |
6 | if "FAUXFACTORY_DISABLE_SEED_RANDOMIZATION" not in os.environ:
7 | random.seed()
8 |
--------------------------------------------------------------------------------
/fauxfactory/factories/booleans.py:
--------------------------------------------------------------------------------
1 | """Method for generating random boolean values."""
2 |
3 | from .choices import gen_choice
4 |
5 |
6 | def gen_boolean():
7 | """Return a random Boolean value.
8 |
9 | :returns: A random Boolean value.
10 | :rtype: bool
11 |
12 | """
13 | choices = (True, False)
14 |
15 | return gen_choice(choices)
16 |
17 |
18 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
19 |
--------------------------------------------------------------------------------
/fauxfactory/factories/choices.py:
--------------------------------------------------------------------------------
1 | """Module to keep methods related to selecting values."""
2 |
3 | import random
4 | import uuid
5 | from collections.abc import Iterable
6 |
7 | from fauxfactory.helpers import check_validation
8 |
9 |
10 | def gen_choice(choices):
11 | """Return a random choice from the available choices.
12 |
13 | :param list choices: List of choices from which select a random value.
14 | :raises: ``ValueError`` if ``choices`` is ``None`` or not ``Iterable`` or
15 | a ``dict``.
16 | :returns: A random element from ``choices``.
17 |
18 | """
19 | # Validation for 'choices'
20 | if choices is None:
21 | raise ValueError("Choices argument cannot be None.")
22 | # We don't want a single dictionary value.
23 | if not isinstance(choices, Iterable) or isinstance(choices, dict):
24 | raise ValueError("Choices argument is not iterable.")
25 | if not choices:
26 | raise ValueError("Choices argument cannot be empty.")
27 | # If only 1 item is present, return it right away
28 | if len(choices) == 1:
29 | return choices[0]
30 |
31 | return random.choice(choices)
32 |
33 |
34 | @check_validation
35 | def gen_uuid():
36 | """Generate a UUID string (universally unique identifiers).
37 |
38 | :returns: Returns a string representation for a UUID.
39 | :rtype: str
40 |
41 | """
42 | return str(uuid.uuid4())
43 |
44 |
45 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
46 |
47 |
48 | def __dir__():
49 | return __all__
50 |
--------------------------------------------------------------------------------
/fauxfactory/factories/dates.py:
--------------------------------------------------------------------------------
1 | """Methods related to generating date/time related values."""
2 |
3 | import datetime
4 | import random
5 |
6 | from fauxfactory.constants import MAX_YEARS, MIN_YEARS
7 |
8 |
9 | def gen_date(min_date=None, max_date=None):
10 | """Return a random date value.
11 |
12 | :param min_date: A valid ``datetime.date`` object.
13 | :param max_date: A valid ``datetime.date`` object.
14 | :raises: ``ValueError`` if arguments are not valid ``datetime.date``
15 | objects.
16 | :returns: Random ``datetime.date`` object.
17 |
18 | """
19 | _min_value = datetime.date.today() - datetime.timedelta(365 * MIN_YEARS)
20 | _max_value = datetime.date.today() + datetime.timedelta(365 * MAX_YEARS)
21 |
22 | if min_date is None:
23 | min_date = _min_value
24 | if max_date is None:
25 | max_date = _max_value
26 |
27 | # Validation
28 | if not isinstance(min_date, datetime.date):
29 | raise ValueError("%s is not a valid datetime.date object")
30 | if not isinstance(max_date, datetime.date):
31 | raise ValueError("%s is not a valid datetime.date object")
32 |
33 | # Check that max_date is not before min_date
34 | assert min_date < max_date
35 |
36 | # Pick a day between min and max dates
37 | diff = max_date - min_date
38 | days = random.randint(0, diff.days)
39 | date = min_date + datetime.timedelta(days=days)
40 |
41 | return date
42 |
43 |
44 | def gen_datetime(min_date=None, max_date=None):
45 | """Return a random datetime value.
46 |
47 | :param min_date: A valid ``datetime.datetime`` object.
48 | :param max_date: A valid ``datetime.datetime`` object.
49 | :raises: ``ValueError`` if arguments are not valid ``datetime.datetime``
50 | objects.
51 | :returns: Random ``datetime.datetime`` object.
52 |
53 | """
54 | _min_value = datetime.datetime.now() - datetime.timedelta(365 * MIN_YEARS)
55 | _max_value = datetime.datetime.now() + datetime.timedelta(365 * MAX_YEARS)
56 |
57 | if min_date is None:
58 | min_date = _min_value
59 | if max_date is None:
60 | max_date = _max_value
61 |
62 | # Validation
63 | if not isinstance(min_date, datetime.datetime):
64 | raise ValueError("%s is not a valid datetime.datetime object")
65 | if not isinstance(max_date, datetime.datetime):
66 | raise ValueError("%s is not a valid datetime.datetime object")
67 |
68 | # Check that max_date is not before min_date
69 | assert min_date < max_date
70 |
71 | # Pick a time between min and max dates
72 | diff = max_date - min_date
73 | seconds = random.randint(0, diff.days * 3600 * 24 + diff.seconds)
74 |
75 | return min_date + datetime.timedelta(seconds=seconds)
76 |
77 |
78 | def gen_time():
79 | """Generate a random time.
80 |
81 | :returns: A random ``datetime.time`` object.
82 |
83 | """
84 | return datetime.time(
85 | random.randint(0, 23),
86 | random.randint(0, 59),
87 | random.randint(0, 59),
88 | random.randint(0, 999999),
89 | )
90 |
91 |
92 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
93 |
94 |
95 | def __dir__():
96 | return __all__
97 |
--------------------------------------------------------------------------------
/fauxfactory/factories/internet.py:
--------------------------------------------------------------------------------
1 | """Methods related to generating internet related values."""
2 |
3 | import random
4 | import re
5 |
6 | from fauxfactory.constants import SCHEMES, SUBDOMAINS, TLDS, VALID_NETMASKS
7 | from fauxfactory.helpers import check_validation
8 |
9 | from .choices import gen_choice
10 | from .strings import gen_alpha
11 |
12 |
13 | def gen_domain(name=None, subdomain=None, tlds=None):
14 | """Generate a random domain name.
15 |
16 | :param str name: Name for your host.
17 | :param str subdomain: Name for the subdomain.
18 | :param str tlds: Top Level Domain Server.
19 | :returns: A random domain name.
20 | :rtype: str
21 |
22 | """
23 | # Generate a new name if needed
24 | if name is None:
25 | name = gen_alpha(8).lower()
26 | # Obtain a random subdomain if needed
27 | if subdomain is None:
28 | subdomain = gen_choice(SUBDOMAINS)
29 | # Obtain a random top level domain if needed
30 | if tlds is None:
31 | tlds = gen_choice(TLDS)
32 |
33 | return f"{name}.{subdomain}.{tlds}"
34 |
35 |
36 | @check_validation
37 | def gen_email(name=None, domain=None, tlds=None):
38 | """Generate a random email address.
39 |
40 | :param str name: Email name.
41 | :param str domain: Domain name.
42 | :param str tlds: Top Level Domain Server.
43 | :returns: An email address.
44 | :rtype: str
45 |
46 | """
47 | # Generate a new name if needed
48 | if name is None:
49 | name = gen_alpha(8)
50 | # Obtain a random domain if needed
51 | if domain is None:
52 | domain = gen_choice(SUBDOMAINS)
53 | # Obtain a random top level domain if needed
54 | if tlds is None:
55 | tlds = gen_choice(TLDS)
56 |
57 | email = f"{name}@{domain}.{tlds}"
58 |
59 | return email
60 |
61 |
62 | @check_validation
63 | def gen_ipaddr(ip3=False, ipv6=False, prefix=()):
64 | """Generate a random IP address.
65 |
66 | You can also specify an IP address prefix if you are interested in
67 | local network address generation, etc.
68 |
69 | :param bool ip3: Whether to generate a 3 or 4 group IP.
70 | :param bool ipv6: Whether to generate IPv6 or IPv4
71 | :param list prefix: A prefix to be used for an IP (e.g. [10, 0, 1]). It
72 | must be an iterable with strings or integers. Can be left
73 | unspecified or empty.
74 | :returns: An IP address.
75 | :rtype: str
76 | :raises: ``ValueError`` if ``prefix`` would lead to no random fields at
77 | all. This means the length that triggers the ``ValueError`` is 4 for
78 | regular IPv4, 3 for IPv4 with ip3 and 8 for IPv6. It will be raised in
79 | any case the prefix length reaches or exceeds those values.
80 |
81 | """
82 | # Set the lengths of the randomly generated sections
83 | if ipv6:
84 | rng = 8
85 | elif ip3:
86 | rng = 3
87 | else:
88 | rng = 4
89 | prefix = [str(field) for field in prefix]
90 | # Prefix reduces number of random fields generated, so subtract the length
91 | # of it from the rng to keep the IP address have correct number of fields
92 | rng -= len(prefix)
93 | if rng == 0:
94 | raise ValueError(f"Prefix {prefix!r} would lead to no randomness at all")
95 | if rng < 0:
96 | raise ValueError(f"Prefix {prefix!r} is too long for this configuration")
97 |
98 | if ipv6:
99 | # StackOverflow.com questions: generate-random-ipv6-address
100 | random_fields = [f"{random.randint(0, 2**16 - 1):x}" for _ in range(rng)]
101 | ipaddr = ":".join(prefix + random_fields)
102 | else:
103 | random_fields = [str(random.randrange(0, 255, 1)) for _ in range(rng)]
104 | ipaddr = ".".join(prefix + random_fields)
105 |
106 | if ip3:
107 | ipaddr = ipaddr + ".0"
108 |
109 | return ipaddr
110 |
111 |
112 | @check_validation
113 | def gen_mac(delimiter=":", multicast=None, locally=None):
114 | """Generate a random MAC address.
115 |
116 | For more information about how unicast or multicast and globally unique and
117 | locally administered MAC addresses are generated check this link
118 | https://en.wikipedia.org/wiki/MAC_address.
119 |
120 | :param str delimiter: Valid MAC delimiter (e.g ':', '-').
121 | :param bool multicast: Indicates if the generated MAC address should be
122 | unicast or multicast. If no value is provided a random one will be
123 | chosen.
124 | :param bool locally: Indicates if the generated MAC address should be
125 | globally unique or locally administered. If no value is provided a
126 | random one will be chosen.
127 | :returns: A random MAC address.
128 | :rtype: str
129 |
130 | """
131 | if delimiter not in [":", "-"]:
132 | raise ValueError(f"Delimiter is not a valid option: {delimiter}")
133 | if multicast is None:
134 | multicast = bool(random.randint(0, 1))
135 | if locally is None:
136 | locally = bool(random.randint(0, 1))
137 |
138 | first_octet = random.randint(0, 255)
139 | if multicast:
140 | # Ensure that the first least significant bit is 1
141 | first_octet |= 0b00000001
142 | else:
143 | # Ensure that the first least significant bit is 0
144 | first_octet &= 0b11111110
145 | if locally:
146 | # Ensure that the second least significant bit is 1
147 | first_octet |= 0b00000010
148 | else:
149 | # Ensure that the second least significant bit is 0
150 | first_octet &= 0b11111101
151 |
152 | octets = [first_octet]
153 | octets.extend(random.randint(0, 255) for _ in range(5))
154 | mac = delimiter.join([f"{octet:02x}" for octet in octets])
155 |
156 | return mac
157 |
158 |
159 | @check_validation
160 | def gen_netmask(min_cidr=1, max_cidr=31):
161 | """Generate a random valid netmask.
162 |
163 | For more info: http://www.iplocation.net/tools/netmask.php
164 |
165 | :param int min_cidr: Inferior CIDR limit
166 | :param int max_cidr: Superior CIDR limit
167 | :returns: The netmask is chosen from
168 | :data:`fauxfactory.constants.VALID_NETMASKS` respecting the CIDR range
169 | :rtype: str
170 | :raises: ``ValueError`` if ``min_cidr`` or ``max_cidr`` have an invalid
171 | value. For example, ``max_cidr`` cannot be 33.
172 |
173 | """
174 | if min_cidr < 0:
175 | raise ValueError(f"min_cidr must be 0 or greater, but is {min_cidr}")
176 | if max_cidr >= len(VALID_NETMASKS):
177 | raise ValueError(
178 | f"max_cidr must be less than {len(VALID_NETMASKS)}, but is {max_cidr}"
179 | )
180 | return VALID_NETMASKS[random.randint(min_cidr, max_cidr)]
181 |
182 |
183 | @check_validation
184 | def gen_url(scheme=None, subdomain=None, tlds=None):
185 | """Generate a random URL address.
186 |
187 | :param str scheme: Either http, https or ftp.
188 | :param str subdomain: A valid subdomain
189 | :param str tlds: A qualified top level domain name (e.g. 'com', 'net')
190 | :raises: ``ValueError`` if arguments are not valid.
191 | :returns: A random URL address.
192 | :rtype: str
193 |
194 | """
195 | # Regex for subdomain names
196 | subdomainator = re.compile(r"^[a-zA-Z0-9][-\w.~]*$")
197 | # Regex for URL scheme
198 | schemenator = re.compile(r"^(https?|ftp)$")
199 | # Regex for TLDS
200 | tldsnator = re.compile(r"^[a-zA-Z]{1,3}$")
201 |
202 | if scheme:
203 | if schemenator.match(scheme) is None:
204 | raise ValueError(f"Protocol {scheme} is not valid.")
205 | else:
206 | scheme = gen_choice(SCHEMES)
207 |
208 | if subdomain:
209 | if subdomainator.match(subdomain) is None:
210 | raise ValueError(f"Subdomain {subdomain} is invalid.")
211 | else:
212 | subdomain = gen_choice(SUBDOMAINS)
213 |
214 | if tlds:
215 | if tldsnator.match(tlds) is None:
216 | raise ValueError(f"TLDS name {tlds} is invalid.")
217 | else:
218 | tlds = gen_choice(TLDS)
219 |
220 | url = f"{scheme}://{subdomain}.{tlds}"
221 |
222 | return url
223 |
224 |
225 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
226 |
227 |
228 | def __dir__():
229 | return __all__
230 |
--------------------------------------------------------------------------------
/fauxfactory/factories/numbers.py:
--------------------------------------------------------------------------------
1 | """Methods that generate random number values."""
2 |
3 | import random
4 | import sys
5 | from functools import partial
6 |
7 | from fauxfactory.helpers import base_repr
8 |
9 |
10 | def gen_integer(min_value=None, max_value=None):
11 | """Return a random integer value based on the current platform.
12 |
13 | :param int min_value: The minimum allowed value.
14 | :param int max_value: The maximum allowed value.
15 | :raises: ``ValueError`` if arguments are not integers or if they are
16 | less or greater than the system's allowed range for integers.
17 | :returns: Returns a random integer value.
18 | :rtype: int
19 |
20 | """
21 | # Platform-specific value range for integers
22 | _min_value = -sys.maxsize - 1
23 | _max_value = sys.maxsize
24 |
25 | if min_value is None:
26 | min_value = _min_value
27 | if max_value is None:
28 | max_value = _max_value
29 |
30 | integer_types = (int,)
31 |
32 | # Perform some validations
33 | if not isinstance(min_value, integer_types) or min_value < _min_value:
34 | raise ValueError(f'"{min_value}" is not a valid minimum.')
35 | if not isinstance(max_value, integer_types) or max_value > _max_value:
36 | raise ValueError(f'"{max_value}" is not a valid maximum.')
37 |
38 | value = random.randint(min_value, max_value)
39 |
40 | return value
41 |
42 |
43 | def gen_negative_integer():
44 | """Return a random negative integer based on the current platform.
45 |
46 | :returns: Returns a random negative integer value.
47 | :rtype: int
48 |
49 | """
50 | max_value = 0
51 |
52 | return gen_integer(max_value=max_value)
53 |
54 |
55 | def gen_positive_integer():
56 | """Return a random positive integer based on the current platform.
57 |
58 | :returns: A random positive integer value.
59 | :rtype: int
60 |
61 | """
62 | min_value = 0
63 |
64 | return gen_integer(min_value=min_value)
65 |
66 |
67 | def gen_number(min_value=None, max_value=None, base=10):
68 | """Return a random number (with representation).
69 |
70 | :returns: A random number with base of .
71 | :rtype: str
72 |
73 | """
74 | return base_repr(
75 | gen_integer(
76 | int(str(min_value), base=base) if min_value is not None else min_value,
77 | int(str(max_value), base=base) if max_value is not None else max_value,
78 | ),
79 | base,
80 | )
81 |
82 |
83 | gen_octagonal = partial(gen_number, base=8)
84 | gen_hexadecimal = partial(gen_number, base=16)
85 |
86 |
87 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
88 |
89 |
90 | def __dir__():
91 | return __all__
92 |
--------------------------------------------------------------------------------
/fauxfactory/factories/strings.py:
--------------------------------------------------------------------------------
1 | """Collection of string generating functions."""
2 |
3 | import random
4 | import string
5 |
6 | from fauxfactory.constants import HTML_TAGS, LOREM_IPSUM_TEXT
7 | from fauxfactory.helpers import (
8 | check_len,
9 | check_validation,
10 | is_positive_int,
11 | unicode_letters_generator,
12 | )
13 |
14 |
15 | def gen_string(str_type, length=None, validator=None, default=None, tries=10):
16 | """Call other string generation methods.
17 |
18 | :param str str_type: The type of string which should be generated.
19 | :param int length: The length of the generated string. Must be 1 or
20 | greater.
21 | :param validator: Function or regex (str).
22 | If a function it must receive one parameter and return True if value
23 | can be used and False of another value need to be generated.
24 | If str it will be used as regex to validate the generated value.
25 | Default is None which will not validate the value.
26 | :param tries: number of times validator must be called before returning
27 | `default`. Default is 10.
28 | :param default: If validator returns false a number of `tries` times, this
29 | value is returned instead. Must be defined if validator is not None
30 | :raises: ``ValueError`` if an invalid ``str_type`` is specified.
31 | :returns: A string.
32 | :rtype: str
33 |
34 | Valid values for ``str_type`` are as follows:
35 |
36 | * alpha
37 | * alphanumeric
38 | * cjk
39 | * cyrillic
40 | * html
41 | * latin1
42 | * numeric
43 | * utf8
44 | * punctuation
45 |
46 | """
47 | str_types_functions = {
48 | "alpha": gen_alpha,
49 | "alphanumeric": gen_alphanumeric,
50 | "cjk": gen_cjk,
51 | "cyrillic": gen_cyrillic,
52 | "html": gen_html,
53 | "latin1": gen_latin1,
54 | "numeric": gen_numeric_string,
55 | "utf8": gen_utf8,
56 | "punctuation": gen_special,
57 | }
58 | str_type_lower = str_type.lower() # do not modify user data
59 | if str_type_lower not in str_types_functions:
60 | raise ValueError(
61 | f"{str_type_lower} is not a supported string type. "
62 | "Valid string types are {0}.".format(",".join(str_types_functions.keys()))
63 | )
64 | method = str_types_functions[str_type_lower]
65 | if length is None:
66 | return method(validator=validator, default=default, tries=tries)
67 | return method(length, validator=validator, default=default, tries=tries)
68 |
69 |
70 | @check_len
71 | @check_validation
72 | def gen_alpha(length=10, start=None, separator=""):
73 | """Return a random string made up of alpha characters.
74 |
75 | :param int length: Length for random data.
76 | :param str start: Random data start with.
77 | :param str separator: Separator character for start and random data.
78 | :returns: A random string made up of alpha characters.
79 | :rtype: str
80 |
81 | """
82 | output_string = "".join(random.choices(string.ascii_letters, k=length))
83 |
84 | if start:
85 | output_string = f"{start}{separator}{output_string}"[:length]
86 | return output_string
87 |
88 |
89 | @check_len
90 | @check_validation
91 | def gen_alphanumeric(length=10, start=None, separator=""):
92 | """Return a random string made up of alpha and numeric characters.
93 |
94 | :param int length: Length for random data.
95 | :param str start: Random data start with.
96 | :param str separator: Separator character for start and random data.
97 | :returns: A random string made up of alpha and numeric characters.
98 | :rtype: str
99 |
100 | """
101 | output_string = "".join(
102 | random.choices(string.ascii_letters + string.digits, k=length)
103 | )
104 |
105 | if start:
106 | output_string = f"{start}{separator}{output_string}"[:length]
107 | return output_string
108 |
109 |
110 | @check_len
111 | @check_validation
112 | def gen_cjk(length=10, start=None, separator=""):
113 | """Return a random string made up of CJK characters.
114 |
115 | (Source: Wikipedia - CJK Unified Ideographs)
116 |
117 | :param int length: Length for random data.
118 | :param str start: Random data start with.
119 | :param str separator: Separator character for start and random data.
120 | :returns: A random string made up of CJK characters.
121 | :rtype: str
122 |
123 | """
124 | # These should represent the ranges for valid CJK characters
125 | unicode_block = (
126 | # CJK Unified Ideographs
127 | (0x4E00, 0x9FFF),
128 | # CJK Unified Ideographs Extension A
129 | (0x3400, 0x4DBF),
130 | # CJK Unified Ideographs Extension B
131 | (0x20000, 0x2A6DF),
132 | # CJK Unified Ideographs Extension C
133 | (0x2A700, 0x2B73F),
134 | # CJK Unified Ideographs Extension D
135 | (0x2B740, 0x2B81F),
136 | )
137 |
138 | output_array = []
139 |
140 | for code_block in unicode_block:
141 | for i in range(*code_block):
142 | output_array.append(i)
143 |
144 | output_string = "".join(map(chr, random.choices(output_array, k=length)))
145 |
146 | if start:
147 | output_string = f"{start}{separator}{output_string}"[0:length]
148 | return output_string
149 |
150 |
151 | @check_len
152 | @check_validation
153 | def gen_cyrillic(length=10, start=None, separator=""):
154 | """Return a random string made up of Cyrillic characters.
155 |
156 | :param int length: Length for random data.
157 | :param str start: Random data start with.
158 | :param str separator: Separator character for start and random data.
159 | :returns: A random string made up of Cyrillic characters.
160 | :rtype: str
161 |
162 | """
163 | # Generate codepoints, then convert the codepoints to a string. The
164 | # valid range of Cyrillic codepoints is 0x0400 - 0x04FF, inclusive.
165 | codepoints = [random.randint(0x0400, 0x04FF) for _ in range(length)]
166 | output_string = "".join(chr(codepoint) for codepoint in codepoints)
167 |
168 | if start:
169 | output_string = f"{start}{separator}{output_string}"[0:length]
170 | return output_string
171 |
172 |
173 | @check_len
174 | @check_validation
175 | def gen_html(length=10, include_tags=True):
176 | """Return a random string made up of html characters.
177 |
178 | :param int length: Length for random data.
179 | :returns: A random string made up of html characters.
180 | :rtype: str
181 |
182 | """
183 | html_tag = random.choice(HTML_TAGS)
184 |
185 | if not include_tags:
186 | if length < 8:
187 | raise ValueError("Cannot generate html with less than 7 chars")
188 | maybe_len = length - len(f"<{html_tag}>{html_tag}>")
189 | if maybe_len <= 0:
190 | length -= 7
191 | html_tag = "a"
192 | else:
193 | length = maybe_len
194 | output_string = f"<{html_tag}>{gen_string('alpha', length)}{html_tag}>"
195 | else:
196 | output_string = f"<{html_tag}>{gen_string('alpha', length)}{html_tag}>"
197 |
198 | return output_string
199 |
200 |
201 | def gen_iplum(words=None, paragraphs=None):
202 | """Return a lorem ipsum string.
203 |
204 | If no arguments are passed, then return the entire default lorem ipsum
205 | string.
206 |
207 | :param int words: The number of words to return.
208 | :param int paragraphs: The number of paragraphs to return.
209 | :raises: ``ValueError`` if ``words`` is not a valid positive integer.
210 | :returns: A ``lorem ipsum`` string containing either the number of
211 | ``words`` or ``paragraphs``, extending and wrapping around the text
212 | as needed to make sure that it has the specified length.
213 | :rtype: str
214 |
215 | """
216 | # Check parameters
217 | if words is None or words == 0:
218 | words = len(LOREM_IPSUM_TEXT.split())
219 | if paragraphs is None:
220 | paragraphs = 1
221 |
222 | if not isinstance(words, int) or words < 0:
223 | raise ValueError("Cannot generate a string with negative number of words.")
224 | is_positive_int(paragraphs)
225 |
226 | # Original Lorem Ipsum string
227 | all_words = LOREM_IPSUM_TEXT.split()
228 | # How many words do we need?
229 | total_words_needed = words * paragraphs
230 |
231 | quotient = int(total_words_needed / len(all_words))
232 | modulus = total_words_needed % len(all_words)
233 |
234 | # Pool of words to use
235 | all_words = all_words * (quotient + modulus)
236 |
237 | result = ""
238 | start_pos = 0
239 | for _ in range(0, paragraphs):
240 | sentence = " ".join(all_words[start_pos : start_pos + words])
241 |
242 | # Remove comma from the end, if it exists
243 | if sentence.endswith(","):
244 | sentence = sentence.rstrip(",")
245 | # Remove period from the end, if it exists
246 | if sentence.endswith("."):
247 | sentence = sentence.rstrip(".")
248 |
249 | # Each sentence should be properly capitalized
250 | cap_sentence = [frag.capitalize() + "." for frag in sentence.split(". ")]
251 |
252 | # Add newline at the end
253 | result += " ".join(cap_sentence) + "\n"
254 |
255 | # Increment positional counter
256 | start_pos += words
257 | return result.rstrip()
258 |
259 |
260 | @check_len
261 | @check_validation
262 | def gen_latin1(length=10, start=None, separator=""):
263 | """Return a random string made up of UTF-8 characters.
264 |
265 | (Font: Wikipedia - Latin-1 Supplement Unicode Block)
266 |
267 | :param int length: Length for random data.
268 | :param str start: Random data start with.
269 | :param str separator: Separator character for start and random data.
270 | :returns: A random string made up of ``Latin1`` characters.
271 | :rtype: str
272 |
273 | """
274 | range0 = range1 = range2 = []
275 | range0 = ["00C0", "00D6"]
276 | range1 = ["00D8", "00F6"]
277 | range2 = ["00F8", "00FF"]
278 | output_array = []
279 |
280 | for i in range(int(range0[0], 16), int(range0[1], 16)):
281 | output_array.append(i)
282 | for i in range(int(range1[0], 16), int(range1[1], 16)):
283 | output_array.append(i)
284 | for i in range(int(range2[0], 16), int(range2[1], 16)):
285 | output_array.append(i)
286 |
287 | output_string = "".join(map(chr, random.choices(output_array, k=length)))
288 |
289 | if start:
290 | output_string = f"{start}{separator}{output_string}"[0:length]
291 | return output_string
292 |
293 |
294 | @check_len
295 | @check_validation
296 | def gen_numeric_string(length=10, start=None, separator=""):
297 | """Return a random string made up of numbers.
298 |
299 | :param int length: Length for random data.
300 | :param str start: Random data start with.
301 | :param str separator: Separator character for start and random data.
302 | :returns: A random string made up of numbers.
303 | :rtype: str
304 |
305 | """
306 | output_string = "".join(random.choices(string.digits, k=length))
307 |
308 | if start:
309 | output_string = f"{start}{separator}{output_string}"[0:length]
310 | return output_string
311 |
312 |
313 | @check_len
314 | @check_validation
315 | def gen_utf8(length=10, smp=True, start=None, separator=""):
316 | """Return a random string made up of UTF-8 letters characters.
317 |
318 | Follows `RFC 3629`_.
319 |
320 | :param int length: Length for random data.
321 | :param str start: Random data start with.
322 | :param str separator: Separator character for start and random data.
323 | :param bool smp: Include Supplementary Multilingual Plane (SMP)
324 | characters
325 | :returns: A random string made up of ``UTF-8`` letters characters.
326 | :rtype: str
327 |
328 | .. _`RFC 3629`: http://www.rfc-editor.org/rfc/rfc3629.txt
329 |
330 | """
331 | unicode_letters = list(unicode_letters_generator(smp))
332 | output_string = "".join(random.choices(unicode_letters, k=length))
333 |
334 | if start:
335 | output_string = f"{start}{separator}{output_string}"[0:length]
336 | return output_string
337 |
338 |
339 | @check_len
340 | @check_validation
341 | def gen_special(length=10, start=None, separator=""):
342 | """Return a random special characters string.
343 |
344 | :param int length: Length for random data.
345 | :param str start: Random data start with.
346 | :param str separator: Separator character for start and random data.
347 | :returns: A random string made up of special characters.
348 | :rtype: str
349 | """
350 | output_string = "".join(random.choices(string.punctuation, k=length))
351 |
352 | if start:
353 | output_string = f"{start}{separator}{output_string}"[0:length]
354 | return output_string
355 |
356 |
357 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
358 |
359 |
360 | def __dir__():
361 | return __all__
362 |
--------------------------------------------------------------------------------
/fauxfactory/factories/systems.py:
--------------------------------------------------------------------------------
1 | """Collection of computer systems generating functions."""
2 |
3 | from copy import deepcopy
4 |
5 | from fauxfactory.constants import FACTS_JSON
6 | from fauxfactory.helpers import is_positive_int
7 |
8 | from .choices import gen_choice, gen_uuid
9 | from .internet import gen_domain, gen_ipaddr, gen_mac, gen_netmask
10 | from .numbers import gen_integer
11 | from .strings import gen_alpha, gen_alphanumeric
12 |
13 |
14 | def add_memory_info(count=None):
15 | """Generate fake memory facts.
16 |
17 | :param int count: The total amount of RAM for a system.
18 | :returns: A dictionary representing memory facts.
19 | :rtype: dict
20 |
21 | """
22 | if count is None:
23 | count = gen_choice(range(4, 128, 2))
24 | else:
25 | is_positive_int(count)
26 |
27 | free_ram = gen_integer(min_value=4, max_value=count)
28 |
29 | return {
30 | "dmi::memory::size": f"{free_ram * 1024}",
31 | "memoryfree": f"{free_ram} GB",
32 | "memoryfree_mb": f"{free_ram * 1024}",
33 | "memorysize": f"{count} GB",
34 | "memorysize_mb": f"{count * 1024}",
35 | "swapfree": f"{free_ram} GB",
36 | "swapfree_mb": f"{free_ram * 1024}",
37 | "swapsize": f"{count} GB",
38 | "swapsize_mb": f"{count * 1024}",
39 | }
40 |
41 |
42 | def add_network_devices():
43 | """Generate fake network device facts.
44 |
45 | :returns: A dictionary representing a Host's network devices.
46 | :rtype: dict
47 |
48 | """
49 | return {
50 | "dhcp_servers": {
51 | "system": gen_ipaddr(),
52 | "enp11s0": gen_ipaddr(),
53 | },
54 | "interfaces": "enp11s0",
55 | "ipaddress": gen_ipaddr(),
56 | "ipaddress6": gen_ipaddr(ipv6=True),
57 | "ipaddress6_enp11s0": gen_ipaddr(ipv6=True),
58 | "macaddress": gen_mac(),
59 | "macaddress_enp11s0": gen_mac(),
60 | "mtu_enp11s0": "1500",
61 | "netmask": gen_netmask(),
62 | "netmask_enp11s0": gen_netmask(),
63 | "netmask_lo": gen_netmask(),
64 | "network_enp11s0": gen_ipaddr(),
65 | "network_lo": "127.0.0.0",
66 | }
67 |
68 |
69 | def add_operating_system(name=None, family=None, major=None, minor=None):
70 | """Generate fake operating system facts.
71 |
72 | :param str name: The name for an operating system.
73 | :param str family: The operating system family.
74 | :param int major: The major release of the operating system.
75 | :param int minor: The minor release of the operating system.
76 | :returns: A dictionary representing an Operating System.
77 | :rtype: dict
78 |
79 | """
80 | if name is None:
81 | name = gen_alpha()
82 | if family is None:
83 | family = gen_alpha()
84 | if major is None:
85 | major = gen_integer(min_value=0, max_value=9)
86 | if minor is None:
87 | minor = gen_integer(min_value=0, max_value=9)
88 | return {
89 | "os": {
90 | "name": name,
91 | "family": family,
92 | "release": {"major": major, "minor": minor, "full": f"{major}.{minor}"},
93 | },
94 | "operatingsystem": name,
95 | "operatingsystemmajrelease": major,
96 | "operatingsystemrelease": f"{major}.{minor}",
97 | "osfamily": family,
98 | "distribution::id": gen_alpha(),
99 | "distribution::name": name,
100 | "distribution::version": f"{major}.{minor}",
101 | }
102 |
103 |
104 | def add_partitions(extra_partitions=None):
105 | """Generate fake partitions facts."""
106 | partitions = {
107 | "partitions": {
108 | "sda1": {
109 | "uuid": gen_uuid(),
110 | "size": "1024000",
111 | "mount": "/boot",
112 | "filesystem": "xfs",
113 | },
114 | }
115 | }
116 |
117 | if extra_partitions is not None:
118 | is_positive_int(extra_partitions)
119 | for idx in range(extra_partitions):
120 | device_id = idx + 1
121 | partitions["partitions"].update(
122 | {
123 | f"sdb{device_id}": {
124 | "size": "975747072",
125 | "filesystem": "LVM2_member",
126 | }
127 | }
128 | )
129 | return partitions
130 |
131 |
132 | def add_processor_info(count=None):
133 | """Generate fake processor facts.
134 |
135 | :param int count: Number of processors for a system.
136 | :returns: A dictionary containing fake processor facts.
137 | :rtype: dict
138 |
139 | """
140 | if count is None:
141 | count = gen_choice(range(2, 16, 2))
142 | else:
143 | is_positive_int(count)
144 |
145 | processors = {
146 | "physicalprocessorcount": count,
147 | "processorcount": count,
148 | "cpu::topology_source": "kernel /sys cpu sibling lists",
149 | "cpu::cpu(s)": count,
150 | "lscpu::cpu(s)": count,
151 | "processors": {
152 | "models": [],
153 | "count": count,
154 | "physicalcount": count,
155 | },
156 | }
157 |
158 | # Add processors info based on total processors
159 | for idx in range(count):
160 | processors[f"processor{idx}"] = "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz"
161 | processors["processors"]["models"].append(
162 | "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz"
163 | )
164 | return processors
165 |
166 |
167 | def gen_system_facts(name=None):
168 | """Generate system facts.
169 |
170 | See https://docs.puppet.com/facter/3.6/core_facts.html for more
171 | information.
172 |
173 | :param str name: Name to be used as the system's hostname.
174 | :returns: A Dictionary representing a system's facts.
175 | :rtype: dict
176 | """
177 | if name is None or name == "":
178 | fqdn = gen_domain()
179 | else:
180 | fqdn = gen_domain(*name.split("."))
181 |
182 | kernel = ".".join([f"{gen_integer(min_value=0, max_value=9)}" for _ in range(3)])
183 |
184 | host = deepcopy(FACTS_JSON)
185 |
186 | host["architecture"] = gen_choice(("i386", "x86_64"))
187 | host["domain"] = ".".join(fqdn.split(".")[1:])
188 | host["fqdn"] = fqdn
189 | host["hostname"] = fqdn.split(".")[0]
190 |
191 | host["hardwareisa"] = host["architecture"]
192 | host["hardwaremodel"] = host["architecture"]
193 | host["kernelmajversion"] = ".".join(kernel.split(".")[:2])
194 | host["kernelrelease"] = (
195 | f"{kernel}-{gen_integer(min_value=0, max_value=999)}.{host['architecture']}"
196 | )
197 | host["kernelversion"] = kernel
198 |
199 | host.update(add_memory_info())
200 |
201 | host.update(add_network_devices())
202 |
203 | host.update(add_operating_system())
204 |
205 | host.update(add_partitions())
206 |
207 | host.update(add_processor_info())
208 |
209 | host["path"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/sbin"
210 |
211 | host["productname"] = f"{gen_alpha()}"
212 | host["dmi::system::product_name"] = host["productname"]
213 | host["dmi::baseboard::product_name"] = host["productname"]
214 | host["serialnumber"] = f"{gen_alphanumeric()}"
215 | host["timezone"] = "EDT"
216 | host["uniqueid"] = f"{gen_alphanumeric()}"
217 | host["uptime_days"] = gen_integer(min_value=1, max_value=1974)
218 | host["uptime_hours"] = host["uptime_days"] * 24
219 | host["uptime_seconds"] = host["uptime_hours"] * 3600
220 | host["uptime"] = f"{host['uptime_days']} days"
221 | host["system_uptime"] = {
222 | "seconds": host["uptime_seconds"],
223 | "hours": host["uptime_hours"],
224 | "days": host["uptime_days"],
225 | "uptime": host["uptime"],
226 | }
227 | host["uuid"] = gen_uuid()
228 | host["dmi::system::uuid"] = host["uuid"]
229 |
230 | return host
231 |
232 |
233 | __all__ = tuple(name for name in locals() if name.startswith("gen_"))
234 |
235 |
236 | def __dir__():
237 | return __all__
238 |
--------------------------------------------------------------------------------
/fauxfactory/facts.json:
--------------------------------------------------------------------------------
1 | {
2 | "architecture": "x86_64",
3 | "augeasversion": "1.4.0",
4 | "bios_release_date": "06/27/2012",
5 | "bios_vendor": "IBM Corp.",
6 | "bios_version": "-[JQE150AUS-1.02]-",
7 | "blockdevice_sda_model": "ST500NM0011",
8 | "blockdevice_sda_size": "500107862016",
9 | "blockdevice_sda_vendor": "ATA",
10 | "blockdevice_sr0_model": "DEVICE 81Y3657",
11 | "blockdevice_sr0_size": "1073741312",
12 | "blockdevice_sr0_vendor": "IBM SATA",
13 | "blockdevices": "sda,sr0",
14 | "boardmanufacturer": "IBM",
15 | "boardproductname": "00D3729",
16 | "boardserialnumber": "29L0B1",
17 | "dhcp_servers": {"system": "10.16.36.29", "enp11s0": "10.16.36.29"},
18 | "domain": "idmqe.lab.eng.bos.redhat.com",
19 | "facterversion": "2.4.6",
20 | "filesystems": "iso9660,xfs",
21 | "fqdn": "cloud-qe-10.idmqe.lab.eng.bos.redhat.com",
22 | "gid": "root",
23 | "hardwareisa": "x86_64",
24 | "hardwaremodel": "x86_64",
25 | "hostname": "cloud-qe-10",
26 | "id": "root",
27 | "interfaces": "docker0,enp0s29u1u1u5,enp11s0,lo,virbr1,virbr1_nic,vnet0,vnet2,vnet3",
28 | "ipaddress": "172.17.0.1",
29 | "ipaddress6": "2620:52:0:1322:3640:b5ff:fe8a:46fc",
30 | "ipaddress6_enp11s0": "2620:52:0:1322:3640:b5ff:fe8a:46fc",
31 | "ipaddress_enp11s0": "10.19.34.41",
32 | "ipaddress_lo": "127.0.0.1",
33 | "is_pe": "false",
34 | "is_virtual": "false",
35 | "kernel": "Linux",
36 | "kernelmajversion": "3.10",
37 | "kernelrelease": "3.10.0-327.el7.x86_64",
38 | "kernelversion": "3.10.0",
39 | "macaddress": "02:42:f3:ac:19:41",
40 | "macaddress_enp11s0": "34:40:b5:8a:46:fc",
41 | "manufacturer": "IBM",
42 | "memoryfree": "6.62 GB",
43 | "memoryfree_mb": "6779.48",
44 | "memorysize": "15.50 GB",
45 | "memorysize_mb": "15876.03",
46 | "mtu_enp11s0": "1500",
47 | "mtu_lo": "65536",
48 | "netmask": "255.255.0.0",
49 | "netmask_enp11s0": "255.255.254.0",
50 | "netmask_lo": "255.0.0.0",
51 | "network_enp11s0": "10.19.34.0",
52 | "network_lo": "127.0.0.0",
53 | "operatingsystem": "RedHat",
54 | "operatingsystemmajrelease": "7",
55 | "operatingsystemrelease": "7.3",
56 | "os": {"name": "RedHat", "family": "RedHat", "release": {"major": "7", "minor": "3", "full": "7.3"}},
57 | "osfamily": "RedHat",
58 | "partitions": {"sda1": {"uuid": "06a5f231-72a2-4f7e-bcfc-663c7c65b2d8", "size": "1024000", "mount": "/boot", "filesystem": "xfs"}, "sda2": {"size": "975747072", "filesystem": "LVM2_member"}},
59 | "path": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/sbin",
60 | "physicalprocessorcount": "1",
61 | "processor0": "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz",
62 | "processor1": "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz",
63 | "processor2": "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz",
64 | "processor3": "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz",
65 | "processorcount": "4",
66 | "processors": {"models": ["Intel(R) Xeon(R) CPU E31220 @ 3.10GHz", "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz", "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz", "Intel(R) Xeon(R) CPU E31220 @ 3.10GHz"], "count": 4, "physicalcount": 1},
67 | "productname": "IBM System X3250 M4 -[2583AC1]-",
68 | "ps": "ps -ef",
69 | "puppet_vardir": "/var/lib/puppet",
70 | "puppetversion": "3.8.6",
71 | "root_home": "/root",
72 | "rubyplatform": "x86_64-linux",
73 | "rubysitedir": "/usr/local/share/ruby/site_ruby/",
74 | "rubyversion": "2.0.0",
75 | "selinux": "true",
76 | "selinux_config_mode": "enforcing",
77 | "selinux_config_policy": "targeted",
78 | "selinux_current_mode": "enforcing",
79 | "selinux_enforced": "true",
80 | "selinux_policyversion": "28",
81 | "serialnumber": "KQ3X4C1",
82 | "sshecdsakey": "AAAAE",
83 | "sshed25519key": "AAAAC",
84 | "sshfp_ecdsa": "SSHFP 3 1 74e732fc8e7bb5a2dbd7a12f640d8f294ef71fa7",
85 | "sshfp_ed25519": "SSHFP 4 1 0cd03c77d5930980f9cc5c9653cdb48eaefe4e08",
86 | "sshfp_rsa": "SSHFP 1 1 c34f4c13c6af5c3d7567d6a26415e15f9e5ca974",
87 | "sshrsakey": "AAAAB3",
88 | "swapfree": "7.70 GB",
89 | "swapfree_mb": "7886.85",
90 | "swapsize": "7.88 GB",
91 | "swapsize_mb": "8064.00",
92 | "system_uptime": {"seconds": 18658441, "hours": 5182, "days": 215, "uptime": "215 days"},
93 | "timezone": "EDT",
94 | "uniqueid": "130a2922",
95 | "uptime": "215 days",
96 | "uptime_days": "215",
97 | "uptime_hours": "5182",
98 | "uptime_seconds": "18658441",
99 | "uuid": "D83DA472-C1E4-3BF2-BC8A-EEC4ACC29391",
100 | "virtual": "physical"
101 | }
102 |
--------------------------------------------------------------------------------
/fauxfactory/helpers.py:
--------------------------------------------------------------------------------
1 | """Collection of helper methods and functions."""
2 |
3 | import re
4 | import unicodedata
5 | from collections import namedtuple
6 | from functools import wraps
7 |
8 | from fauxfactory.constants import VALID_DIGITS
9 |
10 | UnicodePlane = namedtuple("UnicodePlane", ["min", "max"])
11 |
12 | BMP = UnicodePlane(int("0x0000", 16), int("0xffff", 16))
13 | SMP = UnicodePlane(int("0x10000", 16), int("0x1ffff", 16))
14 |
15 |
16 | def base_repr(number, base):
17 | """Return the base representation of a decimal number.
18 |
19 | As shared here: https://stackoverflow.com/a/2267446
20 |
21 | Conversion steps:
22 |
23 | 1) Divide the number by the base
24 | 2) Get the integer quotient for the next iteration
25 | 3) Get the remainder for the hex digit
26 | 4) Repeat the steps until quotient is equal to zero
27 |
28 | :param number: (int) The decimal number to be converted.
29 | :param base: The base to convert.
30 |
31 | :return: The base representation of .
32 | """
33 | if base <= 1:
34 | raise ValueError("Cannot represent number with base smaller than 2.")
35 | if number < 0:
36 | sign = -1
37 | elif number == 0:
38 | return VALID_DIGITS[0]
39 | else:
40 | sign = 1
41 |
42 | number *= sign
43 | digits = []
44 |
45 | while number:
46 | digits.append(VALID_DIGITS[number % base])
47 | number //= base
48 |
49 | if sign < 0:
50 | digits.append("-")
51 |
52 | digits.reverse()
53 |
54 | return "".join(digits)
55 |
56 |
57 | def check_len(fnc):
58 | """Validate generators requiring a `length` argument."""
59 |
60 | @wraps(fnc)
61 | def wrapped(*args, **kwargs):
62 | """Make sure that we verify the `length` argument."""
63 | if args and len(args) == 1:
64 | is_positive_int(args[0])
65 | if "length" in kwargs:
66 | if kwargs.get("length") is not None:
67 | is_positive_int(kwargs.get("length"))
68 |
69 | result = fnc(*args, **kwargs)
70 |
71 | return result
72 |
73 | return wrapped
74 |
75 |
76 | def check_validation(fcn):
77 | """Decorate functions requiring validation.
78 |
79 | Simple decorator to validate values generated by function `fnc`
80 | according to parameters `validator`, `default` and `tries`.
81 |
82 | :param fcn: function to be enhanced
83 | :return: decorated function
84 | """
85 |
86 | @wraps(fcn)
87 | def validate(*args, **kwargs):
88 | """Perform the validation on decorated function."""
89 | validator = kwargs.get("validator")
90 | default = kwargs.get("default")
91 | tries = kwargs.get("tries", 10)
92 | if validator and default is None:
93 | raise ValueError(
94 | 'If "validator" param is defined, "default" parameter must not be None'
95 | )
96 | if validator is None:
97 |
98 | def validator_fcn(_):
99 | """No validation passed."""
100 | return True
101 |
102 | else:
103 | validator_fcn = validator
104 |
105 | if not callable(validator_fcn):
106 |
107 | def regex_validator(value):
108 | """Perform RegEx validation."""
109 | return re.match(validator, value)
110 |
111 | validator_fcn = regex_validator
112 |
113 | # Removing params related to validation but not fcn
114 | for key in ("validator", "default", "tries"):
115 | if key in kwargs:
116 | kwargs.pop(key)
117 |
118 | for _ in range(tries):
119 | value = fcn(*args, **kwargs)
120 | if validator_fcn(value):
121 | return value
122 |
123 | return default
124 |
125 | return validate
126 |
127 |
128 | def is_positive_int(length):
129 | """Check that `length` argument is an integer greater than zero.
130 |
131 | :param int length: The desired length of the string
132 | :raises: `ValueError` if `length` is not an `int` or is less than 1.
133 |
134 | """
135 | if not isinstance(length, int):
136 | raise ValueError(f"{length} is not numeric.")
137 | if length <= 0:
138 | raise ValueError(f"{length} is an invalid length.")
139 |
140 |
141 | def unicode_letters_generator(smp=True):
142 | """Generate unicode characters in the letters category.
143 |
144 | :param bool smp: Include Supplementary Multilingual Plane (SMP)
145 | characters
146 | :return: a generator which will generates all unicode letters available
147 |
148 | """
149 | for i in range(BMP.min, SMP.max if smp else BMP.max):
150 | char = chr(i)
151 | if unicodedata.category(char).startswith("L"):
152 | yield char
153 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "fauxfactory"
3 | version = "3.1.2"
4 | license = { text = "Apache-2.0" }
5 | description = "Generates random data for your tests."
6 | authors = [
7 | { name = "Og B. Maciel", email = "omaciel@ogmaciel.com" }
8 | ]
9 | readme = "README.rst"
10 | requires-python = ">= 3.9"
11 |
12 | keywords = [
13 | "automation",
14 | "data",
15 | "python",
16 | "testing",
17 | ]
18 | classifiers = [
19 | "Development Status :: 5 - Production/Stable",
20 | "Intended Audience :: Developers",
21 | "Natural Language :: English",
22 | "License :: OSI Approved :: Apache Software License",
23 | "Operating System :: OS Independent",
24 | "Programming Language :: Python",
25 | "Programming Language :: Python :: 3.9",
26 | "Programming Language :: Python :: 3.10",
27 | "Programming Language :: Python :: 3.11",
28 | "Programming Language :: Python :: 3.12",
29 | "Topic :: Software Development :: Testing",
30 | ]
31 |
32 | [project.optional-dependencies]
33 | dev = [
34 | "pytest>=8.1.1",
35 | "codecov>=2.1.13",
36 | "pytest-cov>=5.0.0",
37 | "wheel>=0.43.0",
38 | "twine>=5.0.0",
39 | "ruff>=0.3.4",
40 | ]
41 | docs = [
42 | "sphinx",
43 | "sphinx-rtd-theme"
44 | ]
45 |
46 | [project.urls]
47 | Changelog = "https://github.com/omaciel/fauxfactory/blob/master/HISTORY.rst"
48 | Homepage = "https://github.com/omaciel/fauxfactory"
49 | Repository = "https://github.com/omaciel/fauxfactory"
50 |
51 |
52 | [build-system]
53 | requires = ["hatchling"]
54 | build-backend = "hatchling.build"
55 |
56 | [tool.hatch.build]
57 | exclude = ["tests/", "docs/"] # Exclude test and doc directories
58 | include = ["fauxfactory/**/*", "README.rst", "LICENSE"] # Ensure only necessary files are packaged
59 | directory = "dist"
60 |
61 | [tool.hatch.build.targets.sdist]
62 | include = ["fauxfactory/**/*", "README.rst", "LICENSE"]
63 |
64 | [tool.hatch.metadata]
65 | allow-direct-references = true
66 |
67 | [tool.hatch.build.targets.wheel]
68 | packages = ["fauxfactory"]
69 | macos-max-compat = true
70 |
71 | [tool.ruff]
72 | include = ["*.py"]
73 | target-version = "py312"
74 |
75 | [tool.ruff.lint]
76 | select = ["E", "F", "B", "I"]
77 | ignore = ["B018", "E203"]
78 | fixable = ["ALL"]
79 | unfixable = []
80 | dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
81 |
--------------------------------------------------------------------------------
/requirements-dev.lock:
--------------------------------------------------------------------------------
1 | # generated by rye
2 | # use `rye lock` or `rye sync` to update this lockfile
3 | #
4 | # last locked with the following flags:
5 | # pre: false
6 | # features: []
7 | # all-features: false
8 | # with-sources: false
9 |
10 | -e file:.
11 | alabaster==0.7.13
12 | # via sphinx
13 | babel==2.14.0
14 | # via sphinx
15 | certifi==2024.2.2
16 | # via requests
17 | charset-normalizer==3.3.2
18 | # via requests
19 | codecov==2.1.13
20 | coverage==7.4.4
21 | # via codecov
22 | # via pytest-cov
23 | docutils==0.20.1
24 | # via readme-renderer
25 | # via sphinx
26 | idna==3.6
27 | # via requests
28 | imagesize==1.4.1
29 | # via sphinx
30 | importlib-metadata==7.1.0
31 | # via twine
32 | iniconfig==2.0.0
33 | # via pytest
34 | jaraco-classes==3.3.1
35 | # via keyring
36 | jaraco-context==4.3.0
37 | # via keyring
38 | jaraco-functools==4.0.0
39 | # via keyring
40 | jinja2==3.1.3
41 | # via sphinx
42 | keyring==25.0.0
43 | # via twine
44 | markdown-it-py==3.0.0
45 | # via rich
46 | markupsafe==2.1.5
47 | # via jinja2
48 | mdurl==0.1.2
49 | # via markdown-it-py
50 | more-itertools==10.2.0
51 | # via jaraco-classes
52 | # via jaraco-functools
53 | nh3==0.2.17
54 | # via readme-renderer
55 | packaging==24.0
56 | # via pytest
57 | # via sphinx
58 | pkginfo==1.10.0
59 | # via twine
60 | pluggy==1.4.0
61 | # via pytest
62 | pygments==2.17.2
63 | # via readme-renderer
64 | # via rich
65 | # via sphinx
66 | pytest==8.1.1
67 | # via pytest-cov
68 | pytest-cov==5.0.0
69 | readme-renderer==43.0
70 | # via twine
71 | requests==2.31.0
72 | # via codecov
73 | # via requests-toolbelt
74 | # via sphinx
75 | # via twine
76 | requests-toolbelt==1.0.0
77 | # via twine
78 | rfc3986==2.0.0
79 | # via twine
80 | rich==13.7.1
81 | # via twine
82 | ruff==0.3.4
83 | snowballstemmer==2.2.0
84 | # via sphinx
85 | sphinx==7.2.6
86 | # via fauxfactory
87 | sphinxcontrib-applehelp==1.0.4
88 | # via sphinx
89 | sphinxcontrib-devhelp==1.0.2
90 | # via sphinx
91 | sphinxcontrib-htmlhelp==2.0.1
92 | # via sphinx
93 | sphinxcontrib-jsmath==1.0.1
94 | # via sphinx
95 | sphinxcontrib-qthelp==1.0.3
96 | # via sphinx
97 | sphinxcontrib-serializinghtml==1.1.10
98 | # via sphinx
99 | twine==5.0.0
100 | urllib3==2.2.1
101 | # via requests
102 | # via twine
103 | wheel==0.43.0
104 | zipp==3.18.1
105 | # via importlib-metadata
106 |
--------------------------------------------------------------------------------
/requirements.lock:
--------------------------------------------------------------------------------
1 | # generated by rye
2 | # use `rye lock` or `rye sync` to update this lockfile
3 | #
4 | # last locked with the following flags:
5 | # pre: false
6 | # features: []
7 | # all-features: false
8 | # with-sources: false
9 |
10 | -e file:.
11 | alabaster==0.7.16
12 | # via sphinx
13 | babel==2.14.0
14 | # via sphinx
15 | certifi==2024.2.2
16 | # via requests
17 | charset-normalizer==3.3.2
18 | # via requests
19 | docutils==0.20.1
20 | # via sphinx
21 | idna==3.6
22 | # via requests
23 | imagesize==1.4.1
24 | # via sphinx
25 | jinja2==3.1.3
26 | # via sphinx
27 | markupsafe==2.1.5
28 | # via jinja2
29 | packaging==24.0
30 | # via sphinx
31 | pygments==2.17.2
32 | # via sphinx
33 | requests==2.31.0
34 | # via sphinx
35 | snowballstemmer==2.2.0
36 | # via sphinx
37 | sphinx==7.2.6
38 | # via fauxfactory
39 | sphinxcontrib-applehelp==1.0.8
40 | # via sphinx
41 | sphinxcontrib-devhelp==1.0.6
42 | # via sphinx
43 | sphinxcontrib-htmlhelp==2.0.5
44 | # via sphinx
45 | sphinxcontrib-jsmath==1.0.1
46 | # via sphinx
47 | sphinxcontrib-qthelp==1.0.7
48 | # via sphinx
49 | sphinxcontrib-serializinghtml==1.1.10
50 | # via sphinx
51 | urllib3==2.2.1
52 | # via requests
53 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """Unittests for FauxFactory."""
2 |
--------------------------------------------------------------------------------
/tests/test_booleans.py:
--------------------------------------------------------------------------------
1 | """Tests for all boolean generators."""
2 |
3 | import pytest
4 |
5 | from fauxfactory import gen_boolean
6 |
7 |
8 | @pytest.mark.parametrize("item", range(10))
9 | def test_gen_boolean(item):
10 | """Create a random boolean value."""
11 | assert isinstance(gen_boolean(), bool)
12 |
--------------------------------------------------------------------------------
/tests/test_check_validation.py:
--------------------------------------------------------------------------------
1 | """Tests related to generator validation methods."""
2 |
3 | from unittest import mock
4 |
5 | import pytest
6 |
7 | from fauxfactory.helpers import check_validation
8 |
9 | # pylint: disable=invalid-name
10 | # pylint: disable=E1123
11 |
12 |
13 | @check_validation
14 | def decorated_f():
15 | """Test validation method with this simple decorated function."""
16 | return "not a number"
17 |
18 |
19 | def test_no_validator_defined():
20 | """Check result value of decorated function is returned."""
21 | assert decorated_f() == "not a number"
22 |
23 |
24 | def test_validator_defined_with_no_default():
25 | """Check defining validator but not default raises an error."""
26 | with pytest.raises(ValueError):
27 | decorated_f(validator=lambda _: True)
28 |
29 |
30 | def test_regex():
31 | """Check regex validation when validator is a string."""
32 | assert decorated_f(validator=r"\d.*", default="my default") == "my default"
33 | assert decorated_f(validator=r".*", default="my default") == "not a number"
34 |
35 |
36 | def test_callable():
37 | """Check validation when validator is a callable."""
38 | my_callable = mock.Mock(return_value=False)
39 |
40 | # Default of 10 unsuccessful tries
41 | assert decorated_f(validator=my_callable, default="my default") == "my default"
42 | my_callable.assert_called_with("not a number")
43 | assert my_callable.call_count == 10
44 |
45 | # 1 unsuccessful try
46 | my_callable.reset_mock()
47 | assert (
48 | decorated_f(validator=my_callable, default="my default", tries=1)
49 | == "my default"
50 | )
51 | my_callable.assert_called_once_with("not a number")
52 |
53 | # 1 successful try
54 | my_callable.reset_mock()
55 | my_callable.return_value = True
56 | assert (
57 | decorated_f(validator=my_callable, default="my default", tries=10)
58 | == "not a number"
59 | )
60 | my_callable.assert_called_once_with("not a number")
61 |
--------------------------------------------------------------------------------
/tests/test_choices.py:
--------------------------------------------------------------------------------
1 | """Tests for all choice generators."""
2 |
3 | import string
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_choice
8 |
9 |
10 | @pytest.mark.parametrize("item", range(10))
11 | def test_gen_choice_1(item):
12 | """Select a random value from integer values."""
13 | choices = range(5)
14 |
15 | result = gen_choice(choices)
16 | assert result in choices
17 |
18 |
19 | @pytest.mark.parametrize("item", range(10))
20 | def test_gen_choice_2(item):
21 | """Select a random value from alphanumeric values."""
22 | choices = string.ascii_letters + string.digits
23 |
24 | result = gen_choice(choices)
25 | assert result in choices
26 |
27 |
28 | @pytest.mark.parametrize("item", range(10))
29 | def test_gen_choice_3(item):
30 | """Select a random value from short list."""
31 | choices = [
32 | 1,
33 | ]
34 |
35 | result = gen_choice(choices)
36 | assert result == choices[0]
37 |
38 |
39 | @pytest.mark.parametrize("item", range(10))
40 | def test_gen_choice_4(item):
41 | """Select a random value from longer list."""
42 | choices = [1, 2, 3, 9, 10, 11, 100, 101, 102]
43 |
44 | result = gen_choice(choices)
45 | assert result in choices
46 |
47 |
48 | @pytest.mark.parametrize("item", range(10))
49 | def test_gen_choice_5(item):
50 | """Select a random value from short tuple."""
51 | choices = (1,)
52 |
53 | result = gen_choice(choices)
54 | assert result == choices[0]
55 |
56 |
57 | @pytest.mark.parametrize("item", range(10))
58 | def test_gen_choice_6(item):
59 | """Select a random value from longer tuple."""
60 | choices = (
61 | 1,
62 | 2,
63 | 3,
64 | 9,
65 | 10,
66 | 11,
67 | 100,
68 | 101,
69 | 102,
70 | )
71 |
72 | result = gen_choice(choices)
73 | assert result in choices
74 |
75 |
76 | def test_gen_choice_7():
77 | """Select a random value from empty list."""
78 | choices = []
79 |
80 | with pytest.raises(ValueError):
81 | gen_choice(choices)
82 |
83 |
84 | def test_gen_choice_8():
85 | """Select a random value from empty tuple."""
86 | choices = ()
87 |
88 | with pytest.raises(ValueError):
89 | gen_choice(choices)
90 |
91 |
92 | def test_gen_choice_9():
93 | """Select a random value from empty dictionary."""
94 | choices = {}
95 |
96 | with pytest.raises(ValueError):
97 | gen_choice(choices)
98 |
99 |
100 | def test_gen_choice_10():
101 | """Select a random value from single dictionary."""
102 | choices = {"Name": "Bob", "Age": 39}
103 |
104 | with pytest.raises(ValueError):
105 | gen_choice(choices)
106 |
107 |
108 | @pytest.mark.parametrize("item", range(10))
109 | def test_gen_choice_11(item):
110 | """Select a random value from dictionary list."""
111 | choices = [
112 | {"Name": "Bob", "Age": 39},
113 | {"Name": "Alice", "Age": 23},
114 | {"Name": "Pete", "Age": 79},
115 | ]
116 |
117 | result = gen_choice(choices)
118 | assert result in choices
119 |
120 |
121 | @pytest.mark.parametrize("item", range(10))
122 | def test_gen_choice_12(item):
123 | """Select a random value from words list."""
124 | choices = ["green", "yellow", "blue", "white"]
125 |
126 | result = gen_choice(choices)
127 | assert result in choices
128 |
129 |
130 | def test_gen_choice_13():
131 | """Cannot use None for Choice generator."""
132 | choices = None
133 |
134 | with pytest.raises(ValueError):
135 | gen_choice(choices)
136 |
--------------------------------------------------------------------------------
/tests/test_dates.py:
--------------------------------------------------------------------------------
1 | """Tests for date generator."""
2 |
3 | import datetime
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_date
8 | from fauxfactory.constants import MAX_YEARS, MIN_YEARS
9 |
10 |
11 | def test_gen_date_1():
12 | """Create a date with no arguments."""
13 | result = gen_date()
14 | assert isinstance(result, datetime.date)
15 |
16 |
17 | @pytest.mark.parametrize("item", range(10))
18 | def test_gen_date_2(item):
19 | """Create a date with only min_date."""
20 | # Today is...
21 | today = datetime.date.today()
22 | # Five days ago
23 | min_date = today - datetime.timedelta(5)
24 |
25 | assert gen_date(min_date=min_date) >= min_date
26 |
27 |
28 | @pytest.mark.parametrize("item", range(10))
29 | def test_gen_date_3(item):
30 | """Create a date with only max_date."""
31 | # Today is...
32 | today = datetime.date.today()
33 | # Five days into the future
34 | max_date = today + datetime.timedelta(5)
35 |
36 | assert gen_date(max_date=max_date) <= max_date
37 |
38 |
39 | @pytest.mark.parametrize("item", range(10))
40 | def test_gen_date_4(item):
41 | """Create a date with both arguments."""
42 | # Today is...
43 | today = datetime.date.today()
44 | # Five days ago
45 | min_date = today - datetime.timedelta(5)
46 | # Five days into the future
47 | max_date = today + datetime.timedelta(5)
48 |
49 | result = gen_date(min_date=min_date, max_date=max_date)
50 | assert result >= min_date
51 | assert result <= max_date
52 |
53 |
54 | @pytest.mark.parametrize("item", range(20))
55 | def test_gen_date_5(item):
56 | """Create a date with min_date == 'None'."""
57 | # min_date for the platform
58 | min_date = datetime.date.today() - datetime.timedelta(365 * MIN_YEARS)
59 | # max_date = min_date + 1 year
60 | max_date = min_date + datetime.timedelta(365 * 1)
61 |
62 | result = gen_date(min_date=None, max_date=max_date)
63 | assert result.year <= max_date.year
64 | assert result.year >= min_date.year
65 |
66 |
67 | @pytest.mark.parametrize("item", range(20))
68 | def test_gen_date_6(item):
69 | """Create a date with max_date == 'None'."""
70 | # max_date for the platform
71 | max_date = datetime.date.today() + datetime.timedelta(365 * MAX_YEARS)
72 | # min_date = max_date - 1 year
73 | min_date = max_date - datetime.timedelta(365 * 1)
74 |
75 | result = gen_date(min_date=min_date, max_date=None)
76 | assert result.year <= max_date.year
77 | assert result.year >= min_date.year
78 |
79 |
80 | @pytest.mark.parametrize("item", range(20))
81 | def test_gen_date_7(item):
82 | """Create a date with specific date ranges."""
83 | # min_date for the platform
84 | min_date = datetime.date.today() - datetime.timedelta(365 * MIN_YEARS)
85 | # max_date for the platform
86 | max_date = datetime.date.today() + datetime.timedelta(365 * MAX_YEARS)
87 |
88 | result = gen_date(min_date=min_date, max_date=max_date)
89 | assert result.year <= max_date.year
90 | assert result.year >= min_date.year
91 |
92 |
93 | def test_gen_date_8():
94 | """Create a date with non-Date arguments."""
95 | with pytest.raises(ValueError):
96 | gen_date(min_date="", max_date="")
97 |
98 |
99 | def test_gen_date_9():
100 | """Create a date with non-Date arguments."""
101 | with pytest.raises(ValueError):
102 | gen_date(min_date="abc", max_date="def")
103 |
104 |
105 | def test_gen_date_10():
106 | """Create a date with non-Date arguments."""
107 | with pytest.raises(ValueError):
108 | gen_date(min_date=1, max_date=1)
109 |
110 |
111 | def test_gen_date_11():
112 | """Create a date with non-Date arguments."""
113 | with pytest.raises(ValueError):
114 | gen_date(min_date=(1,), max_date=(2, 3, 4))
115 |
116 |
117 | def test_gen_date_12():
118 | """Create a date with non-Date arguments."""
119 | with pytest.raises(ValueError):
120 | gen_date(min_date=["a", "b"], max_date=["c", "d", "e"])
121 |
122 |
123 | def test_gen_date_13():
124 | """Create a date with min_date > max_date."""
125 | # Today is...
126 | today = datetime.date.today()
127 | # Five days into the future
128 | min_date = today + datetime.timedelta(5)
129 |
130 | with pytest.raises(AssertionError):
131 | gen_date(min_date=min_date, max_date=today)
132 |
133 |
134 | def test_gen_date_14():
135 | """max-date must be a Date type."""
136 | with pytest.raises(ValueError):
137 | gen_date(min_date=datetime.date.today(), max_date="foo")
138 |
--------------------------------------------------------------------------------
/tests/test_datetime.py:
--------------------------------------------------------------------------------
1 | """Tests for datetime generator."""
2 |
3 | import datetime
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_datetime
8 | from fauxfactory.constants import MAX_YEARS, MIN_YEARS
9 |
10 |
11 | def test_gen_datetime_1():
12 | """Create a datetime with no arguments."""
13 | assert isinstance(gen_datetime(), datetime.datetime)
14 |
15 |
16 | def test_gen_datetime_2():
17 | """Create a datetime with only min_date."""
18 | # Today is...
19 | today = datetime.datetime.now()
20 | # Five minutes ago
21 | min_date = today - datetime.timedelta(seconds=5 * 60)
22 |
23 | for _ in range(10):
24 | assert gen_datetime(min_date=min_date) >= min_date
25 |
26 |
27 | def test_gen_datetime_3():
28 | """Create a datetime with only max_date."""
29 | # Today is...
30 | today = datetime.datetime.now()
31 | # Five minutes into the future
32 | max_date = today + datetime.timedelta(seconds=5 * 60)
33 |
34 | for _ in range(10):
35 | assert gen_datetime(max_date=max_date) <= max_date
36 |
37 |
38 | def test_gen_datetime_4():
39 | """Create a datetime with a 5-days datetime range."""
40 | # Today is...
41 | today = datetime.datetime.now()
42 | # Five minutes ago
43 | min_date = today - datetime.timedelta(seconds=5 * 60)
44 | # Five minutes into the future
45 | max_date = today + datetime.timedelta(seconds=5 * 60)
46 |
47 | for _ in range(10):
48 | result = gen_datetime(min_date=min_date, max_date=max_date)
49 | assert result >= min_date
50 | assert result <= max_date
51 |
52 |
53 | def test_gen_datetime_5():
54 | """Create a datetime with min_date = None."""
55 | # min_date for the platform
56 | min_date = datetime.datetime.now() - datetime.timedelta(365 * MIN_YEARS)
57 | # max_date = min_date + 1 year
58 | max_date = min_date + datetime.timedelta(365 * 1)
59 |
60 | for _ in range(20):
61 | result = gen_datetime(min_date=None, max_date=max_date)
62 | assert result.year <= max_date.year
63 | assert result.year >= min_date.year
64 |
65 |
66 | def test_gen_datetime_6():
67 | """Create a datetime with max_date == None."""
68 | # max_date for the platform
69 | max_date = datetime.datetime.now() + datetime.timedelta(365 * MAX_YEARS)
70 | # min_date = max_date - 1 year
71 | min_date = max_date - datetime.timedelta(365 * 1)
72 |
73 | for _ in range(20):
74 | result = gen_datetime(min_date=min_date, max_date=None)
75 | assert result.year <= max_date.year
76 | assert result.year >= min_date.year
77 |
78 |
79 | def test_gen_datetime_7():
80 | """Create a datetime with specified datetime ranges."""
81 | # min_date for the platform
82 | min_date = datetime.datetime.now() - datetime.timedelta(365 * MIN_YEARS)
83 | # max_date for the platform
84 | max_date = datetime.datetime.now() + datetime.timedelta(365 * MAX_YEARS)
85 |
86 | for _ in range(20):
87 | result = gen_datetime(min_date=min_date, max_date=max_date)
88 | assert result.year <= max_date.year
89 | assert result.year >= min_date.year
90 |
91 |
92 | def test_gen_datetime_8():
93 | """Create a datetime with non-Date arguments."""
94 | with pytest.raises(ValueError):
95 | gen_datetime(min_date="", max_date="")
96 |
97 |
98 | def test_gen_datetime_9():
99 | """Create a datetime with non-Date arguments."""
100 | with pytest.raises(ValueError):
101 | gen_datetime(min_date="abc", max_date="def")
102 |
103 |
104 | def test_gen_datetime_10():
105 | """Create a datetime with non-Date arguments."""
106 | with pytest.raises(ValueError):
107 | gen_datetime(min_date=1, max_date=1)
108 |
109 |
110 | def test_gen_datetime_11():
111 | """Create a datetime with non-Date arguments."""
112 | with pytest.raises(ValueError):
113 | gen_datetime(min_date=(1,), max_date=(2, 3, 4))
114 |
115 |
116 | def test_gen_datetime_12():
117 | """Create a datetime with non-Date arguments."""
118 | with pytest.raises(ValueError):
119 | gen_datetime(min_date=["a", "b"], max_date=["c", "d", "e"])
120 |
121 |
122 | def test_gen_datetime_13():
123 | """Create a datetime with min_date > max_date."""
124 | # Today is...
125 | today = datetime.datetime.now()
126 | # Five minutes into the future
127 | min_date = today + datetime.timedelta(seconds=5 * 60)
128 |
129 | with pytest.raises(AssertionError):
130 | gen_datetime(min_date=min_date, max_date=today)
131 |
132 |
133 | def test_gen_date_14():
134 | """max-date must be a Datetime type."""
135 | with pytest.raises(ValueError):
136 | gen_datetime(min_date=datetime.datetime.now(), max_date="foo")
137 |
--------------------------------------------------------------------------------
/tests/test_dir.py:
--------------------------------------------------------------------------------
1 | """Check of the __dir__ of the fauxfactory modules/packages.
2 |
3 | These tests are heavily just artificial tests to get 100% coverage.
4 | """
5 |
6 | import os
7 | import os.path
8 | from importlib import import_module
9 |
10 | import fauxfactory.factories
11 |
12 |
13 | def check_all_dired_names_are_getattrable(obj):
14 | """Use dir to list symbol names and check getattr won't raise exception."""
15 | for symbol_name in dir(obj):
16 | getattr(obj, symbol_name)
17 |
18 |
19 | def test_fauxfactory_factories_dir():
20 | """Check dir of fauxfactory factories."""
21 | for d in os.listdir(os.path.dirname(fauxfactory.factories.__file__)):
22 | if d.endswith(".py") and not d.startswith("__"):
23 | name = f".{d[:-3]}"
24 | module = import_module(name, fauxfactory.factories.__package__)
25 | check_all_dired_names_are_getattrable(module)
26 |
27 |
28 | def test_fauxfactory_dir():
29 | """Check dir of fauxfactory itself."""
30 | check_all_dired_names_are_getattrable(fauxfactory)
31 |
--------------------------------------------------------------------------------
/tests/test_domain.py:
--------------------------------------------------------------------------------
1 | """Tests for domain generator."""
2 |
3 | from fauxfactory import gen_domain
4 |
5 |
6 | def test_generate_domain():
7 | """Create valid domain names."""
8 | domain = gen_domain()
9 | assert len(domain.split(".")) == 3
10 |
11 |
12 | def test_generate_domain_with_attributes():
13 | """Create valid domain names."""
14 | domain = gen_domain(name="faux", subdomain="example", tlds="biz")
15 | assert len(domain.split(".")) == 3
16 | assert domain.split(".")[0] == "faux"
17 | assert domain.split(".")[1] == "example"
18 | assert domain.split(".")[2] == "biz"
19 |
20 |
21 | def test_generate_domain_with_name():
22 | """Create valid domain names."""
23 | domain = gen_domain(name="faux")
24 | assert len(domain.split(".")) == 3
25 | assert domain.split(".")[0] == "faux"
26 |
27 |
28 | def test_generate_domain_with_subdomain():
29 | """Create valid domain names."""
30 | domain = gen_domain(subdomain="example")
31 | assert len(domain.split(".")) == 3
32 | assert domain.split(".")[1] == "example"
33 |
34 |
35 | def test_generate_domain_with_tlds():
36 | """Create valid domain names."""
37 | domain = gen_domain(tlds="biz")
38 | assert len(domain.split(".")) == 3
39 | assert domain.split(".")[2] == "biz"
40 |
--------------------------------------------------------------------------------
/tests/test_emails.py:
--------------------------------------------------------------------------------
1 | """Tests for Email generator."""
2 |
3 | import re
4 |
5 | from fauxfactory import gen_email
6 |
7 | REGEX = r"^[a-zA-Z][a-zA-Z-.]*[^.-]@\w*\.[a-zA-Z]{2,3}"
8 |
9 |
10 | def test_gen_email_1():
11 | """Create a random email value."""
12 | # Regex for email validation
13 | emailinator = re.compile(REGEX)
14 | for _ in range(100):
15 | assert emailinator.match(gen_email())
16 |
--------------------------------------------------------------------------------
/tests/test_getattr.py:
--------------------------------------------------------------------------------
1 | """Check of the __getattr__ of the fauxfactory package.
2 |
3 | These tests are heavily just artificial tests to get 100% coverage.
4 | """
5 |
6 | import pytest
7 |
8 | import fauxfactory
9 |
10 |
11 | def test_fauxfactory_getattr():
12 | """Check __getattr__ returns expected objects."""
13 | assert fauxfactory.__getattr__("gen_integer") is fauxfactory.gen_integer
14 |
15 |
16 | def test_fauxfactory_getattr_raises_attributeerror():
17 | """Check __getattr__ raises AttributeError."""
18 | with pytest.raises(AttributeError):
19 | fauxfactory.nonexistentattribute
20 |
--------------------------------------------------------------------------------
/tests/test_html.py:
--------------------------------------------------------------------------------
1 | """Tests for HTML generator."""
2 |
3 | import re
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_html, gen_integer
8 |
9 |
10 | # pylint disable:W0621
11 | @pytest.fixture
12 | def matcher():
13 | """Instantiate a factory and compile a regex.
14 |
15 | The compiled regex can be used to find the contents of an HTML tag.
16 | """
17 | return re.compile("^<.*?>(.*?)$")
18 |
19 |
20 | def test_length_arg_omitted(matcher):
21 | """Generate a random HTML tag with no ``length`` argument."""
22 | match = matcher.search(gen_html())
23 | assert len(match.group(1)) >= 1
24 |
25 |
26 | def test_length_arg_provided(matcher):
27 | """Generate a random HTML tag with ``length`` argument."""
28 | length = gen_integer(1, 25)
29 | match = matcher.search(gen_html(length))
30 | assert len(match.group(1)) == length
31 |
32 |
33 | def test_unicode():
34 | """Generate a random HTML tag."""
35 | assert isinstance(gen_html(), str)
36 |
37 |
38 | # pylint: disable=C0103
39 | def test_generate_html_with_len_less_than_min():
40 | """Cannot generate a HTML string with length less than minimum."""
41 | for value in range(8):
42 | with pytest.raises(ValueError):
43 | gen_html(value, include_tags=False)
44 |
45 |
46 | @pytest.mark.parametrize("length", [8, 10, 12, 20, 100])
47 | def test_generate_html_with_len_more_than_min(length):
48 | """Cannot generate a HTML string with length more than minimum."""
49 | assert length == len(gen_html(length, include_tags=False))
50 |
--------------------------------------------------------------------------------
/tests/test_ipaddress.py:
--------------------------------------------------------------------------------
1 | """Tests for ipaddr generator."""
2 |
3 | import pytest
4 |
5 | from fauxfactory import gen_ipaddr
6 |
7 |
8 | def test_gen_ipv4_1():
9 | """Generate a 3 group IPv4 address."""
10 | result = gen_ipaddr(ip3=True)
11 | assert result.split(".")[-1] == "0"
12 |
13 |
14 | def test_gen_ipv4_2():
15 | """Generate a 4 group IPv4 address."""
16 | result = gen_ipaddr()
17 | assert len(result.split(".")) == 4
18 |
19 |
20 | def test_gen_ipv4_3():
21 | """Generate a 4 group IPv4 address."""
22 | result = gen_ipaddr(ip3=False)
23 | assert len(result.split(".")) == 4
24 |
25 |
26 | def test_gen_ipv4_4():
27 | """Generate a 4 group IPv4 address."""
28 | result = gen_ipaddr(ip3=False, ipv6=False)
29 | assert len(result.split(".")) == 4
30 |
31 |
32 | def test_gen_ipv4_5():
33 | """Generate a 4 group IPv4 address with good prefix."""
34 | result = gen_ipaddr(ip3=False, ipv6=False, prefix=[10])
35 | assert len(result.split(".")) == 4
36 | assert result.startswith("10.")
37 |
38 |
39 | def test_gen_ipv4_6():
40 | """Generate a 4 group IPv4 address with good prefix."""
41 | result = gen_ipaddr(ip3=False, ipv6=False, prefix=[10, 10])
42 | assert len(result.split(".")) == 4
43 | assert result.startswith("10.10.")
44 |
45 |
46 | def test_gen_ipv4_7():
47 | """Generate a 4 group IPv4 address with good prefix."""
48 | result = gen_ipaddr(ip3=False, ipv6=False, prefix=[10, 10, 10])
49 | assert len(result.split(".")) == 4
50 | assert result.startswith("10.10.10.")
51 |
52 |
53 | def test_gen_ipv4_8():
54 | """Generate a 4 group IPv4 address with prefix disabling randomness."""
55 | with pytest.raises(ValueError):
56 | gen_ipaddr(ip3=False, ipv6=False, prefix=[10, 10, 10, 10])
57 |
58 |
59 | def test_gen_ipv4_9():
60 | """Generate a 4 group IPv4 address with prefix too long."""
61 | with pytest.raises(ValueError):
62 | gen_ipaddr(ip3=False, ipv6=False, prefix=[10, 10, 10, 10, 10])
63 |
64 |
65 | def test_gen_ipv4_10():
66 | """Generate a 3 group IPv4 address with good prefix."""
67 | result = gen_ipaddr(ip3=True, ipv6=False, prefix=[10, 10])
68 | assert len(result.split(".")) == 4
69 | assert result.startswith("10.10.")
70 | assert result.endswith(".0")
71 |
72 |
73 | def test_gen_ipv4_11():
74 | """Generate a 3 group IPv4 address with prefix disabling randomness."""
75 | with pytest.raises(ValueError):
76 | gen_ipaddr(ip3=True, ipv6=False, prefix=[10, 10, 10])
77 |
78 |
79 | def test_gen_ipv4_12():
80 | """Generate a 3 group IPv4 address with prefix too long."""
81 | with pytest.raises(ValueError):
82 | gen_ipaddr(ip3=True, ipv6=False, prefix=[10, 10, 10, 10])
83 |
84 |
85 | def test_gen_ipv6_1():
86 | """Generate a IPv6 address."""
87 | result = gen_ipaddr(ipv6=True)
88 | assert len(result.split(":")) == 8
89 |
90 |
91 | def test_gen_ipv6_2():
92 | """Generate a IPv6 address."""
93 | result = gen_ipaddr(ip3=True, ipv6=True)
94 | assert len(result.split(":")) == 8
95 |
96 |
97 | def test_gen_ipv6_3():
98 | """Generate a IPv6 address with custom prefix."""
99 | result = gen_ipaddr(ipv6=True, prefix=["e2d3"])
100 | assert len(result.split(":")) == 8
101 | assert result.startswith("e2d3:")
102 |
103 |
104 | def test_gen_ipv6_4():
105 | """Generate a IPv6 address with custom (very long) prefix."""
106 | prefix = 7 * ["e2d3"]
107 | result = gen_ipaddr(ipv6=True, prefix=prefix)
108 | assert len(result.split(":")) == 8
109 | assert result.startswith(":".join(prefix))
110 |
111 |
112 | def test_gen_ipv6_5():
113 | """Generate a IPv6 address with too long prefix."""
114 | prefix = 8 * ["e2d3"]
115 | with pytest.raises(ValueError):
116 | gen_ipaddr(ipv6=True, prefix=prefix)
117 |
118 |
119 | def test_gen_ipv6_6():
120 | """Generate a IPv6 address with even longer prefix."""
121 | prefix = 9 * ["e2d3"]
122 | with pytest.raises(ValueError):
123 | gen_ipaddr(ipv6=True, prefix=prefix)
124 |
--------------------------------------------------------------------------------
/tests/test_lorem_ipsum.py:
--------------------------------------------------------------------------------
1 | """Tests for Lorem Ipsum generator."""
2 |
3 | import random
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_iplum
8 | from fauxfactory.constants import LOREM_IPSUM_TEXT
9 |
10 |
11 | def test_gen_loremipsum_1():
12 | """Create a complete lorem ipsum string."""
13 | result = gen_iplum()
14 | assert result == LOREM_IPSUM_TEXT
15 | assert result.startswith("Lorem ipsum")
16 |
17 |
18 | def test_gen_loremipsum_2():
19 | """Create a lorem ipsum string with fixed number of words."""
20 | for _ in range(20):
21 | length = random.randint(1, 500)
22 | result = gen_iplum(words=length)
23 | assert len(result.split()) == length
24 |
25 |
26 | def test_gen_loremipsum_3():
27 | """Create a lorem ipsum string with fixed number of paragraphs."""
28 | for _ in range(20):
29 | length = random.randint(1, 20)
30 | result = gen_iplum(paragraphs=length)
31 | assert len(result.split("\n")) == length
32 |
33 |
34 | def test_gen_loremipsum_4():
35 | """Create a lorem ipsum string with zero words."""
36 | result = gen_iplum(words=0)
37 | assert result == LOREM_IPSUM_TEXT
38 |
39 |
40 | def test_gen_loremipsum_5():
41 | """Create a lorem ipsum string with zero paragraphs."""
42 | with pytest.raises(ValueError):
43 | gen_iplum(paragraphs=0)
44 |
45 |
46 | def test_gen_loremipsum_6():
47 | """Create a lorem ipsum string with 1 word and 0 paragragh."""
48 | with pytest.raises(ValueError):
49 | gen_iplum(words=1, paragraphs=0)
50 |
51 |
52 | def test_gen_loremipsum_7():
53 | """Create a lorem ipsum string with 1 word and 1 paragragh."""
54 | result = gen_iplum(words=1, paragraphs=1)
55 | assert len(result.split()) == 1
56 | assert len(result.split()) == 1
57 |
58 |
59 | def test_gen_loremipsum_8():
60 | """Create a lorem ipsum string with non-integer words."""
61 | with pytest.raises(ValueError):
62 | gen_iplum(words="a")
63 |
64 |
65 | def test_gen_loremipsum_9():
66 | """Create a lorem ipsum string with non-integer paragraphs."""
67 | with pytest.raises(ValueError):
68 | gen_iplum(paragraphs="a")
69 |
70 |
71 | def test_gen_loremipsum_10():
72 | """Create a lorem ipsum string with random words/paragraphs."""
73 | for _ in range(20):
74 | words = random.randint(1, 500)
75 | paragraphs = random.randint(1, 500)
76 | result = gen_iplum(words=words, paragraphs=paragraphs)
77 | assert len(result.split("\n")) == paragraphs
78 | for sentence in result.split("\n"):
79 | assert len(sentence.split()) == words
80 |
--------------------------------------------------------------------------------
/tests/test_macs.py:
--------------------------------------------------------------------------------
1 | """Tests for MAC generator."""
2 |
3 | import random
4 | import re
5 | import string
6 |
7 | import pytest
8 |
9 | from fauxfactory import gen_mac
10 |
11 | MAC = re.compile("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$")
12 |
13 |
14 | def test_gen_mac_1():
15 | r"""Generate a MAC address using \":\" as the delimiter."""
16 | result = gen_mac()
17 | assert len(result.split(":")) == 6
18 | assert MAC.match(result) is not None
19 |
20 |
21 | def test_gen_mac_2():
22 | r"""Generate a MAC address using \":\" as the delimiter."""
23 | result = gen_mac(delimiter=":")
24 | assert len(result.split(":")) == 6
25 | assert MAC.match(result) is not None
26 |
27 |
28 | def test_gen_mac_3():
29 | r"""Generate a MAC address using \"-\" as the delimiter."""
30 | result = gen_mac(delimiter="-")
31 | assert len(result.split("-")) == 6
32 | assert MAC.match(result) is not None
33 |
34 |
35 | def test_gen_mac_4():
36 | r"""Generate a MAC address using \".\" as the delimiter."""
37 | with pytest.raises(ValueError):
38 | gen_mac(delimiter=".")
39 |
40 |
41 | def test_gen_mac_5():
42 | r"""Generate a MAC address using \" \" as the delimiter."""
43 | with pytest.raises(ValueError):
44 | gen_mac(delimiter=" ")
45 |
46 |
47 | def test_gen_mac_6():
48 | """Generate a MAC address using a number as the delimiter."""
49 | with pytest.raises(ValueError):
50 | gen_mac(delimiter=random.randint(0, 10))
51 |
52 |
53 | def test_gen_mac_7():
54 | """Generate a MAC address using a letter as the delimiter."""
55 | with pytest.raises(ValueError):
56 | gen_mac(delimiter=random.choice(string.ascii_letters))
57 |
58 |
59 | # pylint: disable=C0103
60 | def test_gen_mac_unicast_globally_unique():
61 | """Generate a unicast and globally unique MAC address."""
62 | mac = gen_mac(multicast=False, locally=False)
63 | first_octect = int(mac.split(":", 1)[0], 16)
64 | mask = 0b00000011
65 | assert first_octect & mask == 0
66 |
67 |
68 | def test_gen_mac_multicast_globally_unique():
69 | """Generate a multicast and globally unique MAC address."""
70 | mac = gen_mac(multicast=True, locally=False)
71 | first_octect = int(mac.split(":", 1)[0], 16)
72 | mask = 0b00000011
73 | assert first_octect & mask == 1
74 |
75 |
76 | def test_gen_mac_unicast_locally_administered():
77 | """Generate a unicast and locally administered MAC address."""
78 | mac = gen_mac(multicast=False, locally=True)
79 | first_octect = int(mac.split(":", 1)[0], 16)
80 | mask = 0b00000011
81 | assert first_octect & mask == 2
82 |
83 |
84 | def test_gen_mac_multicast_locally_administered():
85 | """Generate a multicast and locally administered MAC address."""
86 | mac = gen_mac(multicast=True, locally=True)
87 | first_octect = int(mac.split(":", 1)[0], 16)
88 | mask = 0b00000011
89 | assert first_octect & mask == 3
90 |
--------------------------------------------------------------------------------
/tests/test_netmasks.py:
--------------------------------------------------------------------------------
1 | """Tests for the netmask generator."""
2 |
3 | import re
4 |
5 | import pytest
6 |
7 | from fauxfactory import gen_netmask
8 | from fauxfactory.constants import VALID_NETMASKS
9 |
10 | NETMASK_REGEX = re.compile(
11 | "((255.){3}(0|128|192|224|240|248|252|254|255))|"
12 | "((255.){2}(0|128|192|224|240|248|252|254).0)|"
13 | "(255.(0|128|192|224|240|248|252|254)(.0){2})|"
14 | "((0|128|192|224|240|248|252|254)(.0){3})"
15 | )
16 |
17 |
18 | def test_gen_netmask():
19 | """Test if gen_netmask generates valid values."""
20 | result = gen_netmask()
21 | assert len(result.split(".")) == 4
22 | assert NETMASK_REGEX.match(result) is not None
23 |
24 |
25 | def test_gen_netmask_boundary():
26 | """Test gen_netmask boundary cases."""
27 | assert gen_netmask(0, 0) == "0.0.0.0"
28 | assert gen_netmask(32, 32) == "255.255.255.255"
29 | with pytest.raises(ValueError):
30 | gen_netmask(-1, 16)
31 | with pytest.raises(ValueError):
32 | gen_netmask(16, 33)
33 |
34 |
35 | def test_valid_netmasks():
36 | """Test if VALID_NETMASKS constant have valid netmask values."""
37 | for netmask in VALID_NETMASKS:
38 | assert NETMASK_REGEX.match(netmask) is not None
39 |
--------------------------------------------------------------------------------
/tests/test_numbers.py:
--------------------------------------------------------------------------------
1 | """Tests for all number generators."""
2 |
3 | import sys
4 | from collections import namedtuple
5 | from functools import partial
6 |
7 | import pytest
8 |
9 | from fauxfactory import (
10 | gen_hexadecimal,
11 | gen_integer,
12 | gen_negative_integer,
13 | gen_number,
14 | gen_octagonal,
15 | gen_positive_integer,
16 | )
17 | from fauxfactory.helpers import VALID_DIGITS, base_repr
18 |
19 | GenFuncDataSet = namedtuple("GenFuncDataSet", ["gen_func", "expect_type", "base"])
20 | GenFuncDataSets = [
21 | GenFuncDataSet(gen_hexadecimal, str, 16),
22 | GenFuncDataSet(gen_integer, int, 10),
23 | GenFuncDataSet(gen_octagonal, str, 8),
24 | GenFuncDataSet(partial(gen_number, base=2), str, 2),
25 | GenFuncDataSet(partial(gen_number, base=5), str, 5),
26 | GenFuncDataSet(partial(gen_number, base=19), str, 19),
27 | ]
28 |
29 |
30 | @pytest.mark.parametrize("base", [0, 1])
31 | def test_base_repr_small_base(base):
32 | """Testing the base_repr helper."""
33 | with pytest.raises(ValueError):
34 | base_repr(1, base)
35 |
36 |
37 | @pytest.mark.parametrize(
38 | "number, base, result",
39 | [
40 | (10, 10, "10"),
41 | (1, 2, "1"),
42 | (7, 6, "11"),
43 | (16, 8, "20"),
44 | (3, 3, "10"),
45 | (21, 20, "11"),
46 | (123, 12, "a3"),
47 | (139, 16, "8b"),
48 | (0, 10, "0"),
49 | ],
50 | )
51 | def test_base_repr(number, base, result):
52 | """Return base representation for a number."""
53 | assert base_repr(number, base) == result
54 |
55 |
56 | @pytest.mark.parametrize("data_set", GenFuncDataSets)
57 | def test_gen_number_1(data_set):
58 | """Create a random number with no range limits."""
59 | result = data_set.gen_func()
60 | assert isinstance(result, data_set.expect_type)
61 | assert set(str(result).lower()).issubset(set(VALID_DIGITS[: data_set.base] + "-"))
62 |
63 |
64 | @pytest.mark.parametrize("data_set", GenFuncDataSets)
65 | def test_gen_number_2(data_set):
66 | """Create a random number with set minimum limit."""
67 | try:
68 | # Change system max int to a smaller number
69 | old_sys_maxsize = sys.maxsize
70 | sys.maxsize = 5
71 |
72 | for _ in range(10):
73 | result = int(str(data_set.gen_func(min_value=1)), base=data_set.base)
74 | assert result <= sys.maxsize
75 | assert result >= 1
76 | finally:
77 | # Reset system max int back to original value
78 | sys.maxsize = old_sys_maxsize
79 |
80 |
81 | @pytest.mark.parametrize("data_set", GenFuncDataSets)
82 | def test_gen_number_3(data_set):
83 | """Create a random number with set maximum limit."""
84 | try:
85 | # Change system max int to a smaller number
86 | old_sys_maxsize = sys.maxsize
87 | sys.maxsize = 1000
88 | min_value = -sys.maxsize - 1
89 |
90 | max_value_based = (
91 | 1000 if data_set.gen_func is gen_integer else base_repr(1000, data_set.base)
92 | )
93 | for _ in range(10):
94 | result = int(
95 | str(data_set.gen_func(max_value=max_value_based)), base=data_set.base
96 | )
97 | assert result >= min_value
98 | assert result <= 1000
99 | finally:
100 | # Reset system max int back to original value
101 | sys.maxsize = old_sys_maxsize
102 |
103 |
104 | @pytest.mark.parametrize("data_set", GenFuncDataSets)
105 | def test_gen_number_4(data_set):
106 | """Create a random number with set min/max limits."""
107 | max_value_based = (
108 | 3000 if data_set.gen_func is gen_integer else base_repr(3000, data_set.base)
109 | )
110 | for _ in range(10):
111 | result = int(
112 | str(data_set.gen_func(min_value=1, max_value=max_value_based)),
113 | base=data_set.base,
114 | )
115 | assert result >= 1
116 | assert result <= 3000
117 |
118 |
119 | def test_gen_integer_1():
120 | """Create a random integer with disallowed minimum limit."""
121 | # This is lower than allowed platform minimum
122 | low_min = -sys.maxsize - 2
123 |
124 | with pytest.raises(ValueError):
125 | gen_integer(min_value=low_min)
126 |
127 |
128 | def test_gen_integer_2():
129 | """Create a random integer with disallowed maximum limit."""
130 | # This is greater than allowed platform maximum
131 | high_max = sys.maxsize + 1
132 |
133 | with pytest.raises(ValueError):
134 | gen_integer(max_value=high_max)
135 |
136 |
137 | def test_gen_integer_7_0():
138 | """Create a random integer using empty strings as args."""
139 | with pytest.raises(ValueError):
140 | gen_integer(min_value="")
141 |
142 |
143 | def test_gen_integer_7_1():
144 | """Create a random integer using empty strings as args."""
145 | with pytest.raises(ValueError):
146 | gen_integer(max_value="")
147 |
148 |
149 | def test_gen_integer_7_2():
150 | """Create a random integer using empty strings as args."""
151 | with pytest.raises(ValueError):
152 | gen_integer(min_value="", max_value="")
153 |
154 |
155 | def test_gen_integer_8_0():
156 | """Create a random integer using whitespace as args."""
157 | with pytest.raises(ValueError):
158 | gen_integer(min_value=" ")
159 |
160 |
161 | def test_gen_integer_8_1():
162 | """Create a random integer using whitespace as args."""
163 | with pytest.raises(ValueError):
164 | gen_integer(max_value=" ")
165 |
166 |
167 | def test_gen_integer_8_2():
168 | """Create a random integer using whitespace as args."""
169 | with pytest.raises(ValueError):
170 | gen_integer(min_value=" ", max_value=" ")
171 |
172 |
173 | def test_gen_integer_9_0():
174 | """Create a random integer using alpha strings as args."""
175 | with pytest.raises(ValueError):
176 | gen_integer(min_value="a")
177 |
178 |
179 | def test_gen_integer_9_1():
180 | """Create a random integer using alpha strings as args."""
181 | with pytest.raises(ValueError):
182 | gen_integer(max_value="a")
183 |
184 |
185 | def test_gen_integer_9_2():
186 | """Create a random integer using alpha strings as args."""
187 | with pytest.raises(ValueError):
188 | gen_integer(min_value="a", max_value="b")
189 |
190 |
191 | def test_gen_positive_integer_1():
192 | """Create a random positive integer."""
193 | assert gen_positive_integer() >= 0
194 |
195 |
196 | def test_gen_negative_integer_1():
197 | """Create a random negative integer."""
198 | assert gen_negative_integer() <= 0
199 |
--------------------------------------------------------------------------------
/tests/test_strings.py:
--------------------------------------------------------------------------------
1 | """Tests for all string generators."""
2 |
3 | import string
4 | import unicodedata
5 | from random import randint
6 |
7 | import pytest
8 |
9 | from fauxfactory import (
10 | gen_alpha,
11 | gen_alphanumeric,
12 | gen_cjk,
13 | gen_cyrillic,
14 | gen_html,
15 | gen_latin1,
16 | gen_numeric_string,
17 | gen_special,
18 | gen_string,
19 | gen_utf8,
20 | )
21 | from fauxfactory.helpers import BMP, unicode_letters_generator
22 |
23 | GENERATORS = [
24 | gen_html,
25 | gen_alpha,
26 | gen_alphanumeric,
27 | gen_cjk,
28 | gen_cyrillic,
29 | gen_latin1,
30 | gen_numeric_string,
31 | gen_utf8,
32 | gen_special,
33 | ]
34 |
35 | STRING_TYPES = [
36 | "html",
37 | "alpha",
38 | "alphanumeric",
39 | "cjk",
40 | "cyrillic",
41 | "latin1",
42 | "numeric",
43 | "utf8",
44 | "punctuation",
45 | ]
46 |
47 |
48 | @pytest.mark.parametrize("fnc", GENERATORS)
49 | def test_positive_string(fnc):
50 | """Default string generated is longer than zero characters."""
51 | assert fnc()
52 |
53 |
54 | @pytest.mark.parametrize("fnc", GENERATORS[1:])
55 | def test_fixed_length_positional(fnc):
56 | """String generated has correct length of characters."""
57 | assert len(fnc(10)) == 10
58 |
59 |
60 | @pytest.mark.parametrize("fnc", GENERATORS[1:])
61 | def test_fixed_length_keyword(fnc):
62 | """String generated has correct length of characters."""
63 | assert len(fnc(length=10)) == 10
64 |
65 |
66 | @pytest.mark.parametrize("fnc", GENERATORS)
67 | def test_negative_length(fnc):
68 | """Cannot generate string with negative length of characters."""
69 | with pytest.raises(ValueError):
70 | fnc(-1)
71 |
72 |
73 | @pytest.mark.parametrize("fnc", GENERATORS)
74 | def test_zero_length(fnc):
75 | """Cannot generate string with zero length of characters."""
76 | with pytest.raises(ValueError):
77 | fnc(0)
78 |
79 |
80 | @pytest.mark.parametrize("fnc", GENERATORS)
81 | def test_alpha_length(fnc):
82 | """Cannot generate string with alpha length of characters."""
83 | with pytest.raises(ValueError):
84 | fnc("a")
85 |
86 |
87 | @pytest.mark.parametrize("fnc", GENERATORS)
88 | def test_alphanumeric_length(fnc):
89 | """Cannot generate string with alphanumeric length of characters."""
90 | with pytest.raises(ValueError):
91 | fnc("-1")
92 |
93 |
94 | @pytest.mark.parametrize("fnc", GENERATORS)
95 | def test_empty_length(fnc):
96 | """Cannot generate string with empty length of characters."""
97 | with pytest.raises(ValueError):
98 | fnc("")
99 |
100 |
101 | @pytest.mark.parametrize("fnc", GENERATORS)
102 | def test_space_length(fnc):
103 | """Cannot generate string with space length of characters."""
104 | with pytest.raises(ValueError):
105 | fnc(" ")
106 |
107 |
108 | @pytest.mark.parametrize("fnc", STRING_TYPES)
109 | def test_gen_string(fnc):
110 | """Use `gen_string` to generate supported string."""
111 | assert gen_string(fnc)
112 |
113 |
114 | # pylint: disable=invalid-name
115 | @pytest.mark.parametrize("fnc", STRING_TYPES[1:])
116 | def test_gen_string_fixed_length_positional(fnc):
117 | """Use `gen_string` to generate supported string with expected length."""
118 | assert len(gen_string(fnc, 5)) == 5
119 |
120 |
121 | # pylint: disable=invalid-name
122 | @pytest.mark.parametrize("fnc", STRING_TYPES[1:])
123 | def test_gen_string_fixed_length_keyword(fnc):
124 | """Use `gen_string` to generate supported string with explict `length`."""
125 | assert len(gen_string(fnc, length=5)) == 5
126 |
127 |
128 | def test_chars_in_letters_category():
129 | """Unicode letters generator generates only unicode letters."""
130 | # Categories extracted from section 5.5.1 of
131 | # http://www.unicode.org/reports/tr44/tr44-4.html
132 | for char in unicode_letters_generator():
133 | assert unicodedata.category(char) in ("Lu", "Ll", "Lt", "Lm", "Lo")
134 |
135 |
136 | def test_bmp_chars_only():
137 | """Unicode letters generator generates only BMP unicode letters."""
138 | for char in gen_utf8(length=50, smp=False):
139 | assert ord(char) <= BMP.max
140 |
141 |
142 | def test_invalid_string_type():
143 | """Only valid string types can be generated."""
144 | with pytest.raises(ValueError):
145 | gen_string("foo")
146 |
147 |
148 | def test_special_string():
149 | """Assert that only punctuation strings are returned."""
150 | VALID_CHARS = string.punctuation
151 | special_str = gen_special()
152 | for char in special_str:
153 | assert char in VALID_CHARS
154 |
155 |
156 | @pytest.mark.parametrize("fnc", GENERATORS[1:])
157 | def test_start_string(fnc):
158 | """String generated has start with specific keyword."""
159 | start = fnc(randint(1, 5))
160 | separator = fnc(1)
161 | random_str = fnc(start=start, separator=separator)
162 | assert start == random_str[: len(start)]
163 | assert separator == random_str[len(start)]
164 | assert len(random_str) == 10
165 |
--------------------------------------------------------------------------------
/tests/test_system_facts.py:
--------------------------------------------------------------------------------
1 | """Tests for system facts generator."""
2 |
3 | import re
4 |
5 | from fauxfactory import gen_system_facts
6 |
7 | REGEX = r"^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$"
8 |
9 |
10 | def test_gen_system_facts():
11 | """Create a random system facts."""
12 | # Regex for domain validation
13 | validator = re.compile(REGEX)
14 | facts = gen_system_facts()
15 |
16 | assert validator.match(facts["fqdn"])
17 |
18 |
19 | def test_gen_system_facts_with_name():
20 | """Create a random system facts using a name."""
21 | # Regex for domain validation
22 | facts = gen_system_facts(name="faux")
23 |
24 | assert facts["fqdn"].startswith("faux")
25 | assert facts["hostname"] == "faux"
26 |
27 |
28 | def test_gen_system_facts_with_name_subdomain():
29 | """Create a random system facts using name and subdomain."""
30 | # Regex for domain validation
31 | facts = gen_system_facts(name="faux.example")
32 |
33 | assert facts["fqdn"].startswith("faux.example")
34 | assert facts["hostname"] == "faux"
35 | assert facts["domain"].startswith("example")
36 |
37 |
38 | def test_gen_system_facts_with_fqdn():
39 | """Create a random system facts using FQDN."""
40 | # Regex for domain validation
41 | validator = re.compile(REGEX)
42 | facts = gen_system_facts(name="faux.example.com")
43 |
44 | assert validator.match(facts["fqdn"])
45 | assert facts["fqdn"] == "faux.example.com"
46 | assert facts["domain"] == "example.com"
47 | assert facts["hostname"] == "faux"
48 |
--------------------------------------------------------------------------------
/tests/test_system_helpers.py:
--------------------------------------------------------------------------------
1 | """Tests for system facts helpers."""
2 |
3 | import pytest
4 |
5 | from fauxfactory.factories.systems import (
6 | add_memory_info,
7 | add_network_devices,
8 | add_operating_system,
9 | add_partitions,
10 | add_processor_info,
11 | )
12 |
13 |
14 | # Memory
15 | def test_add_random_memory():
16 | """Get facts for random memory."""
17 | facts = add_memory_info()
18 | total_memory_mb = int(facts["memorysize_mb"])
19 | total_free_memory_mb = int(facts["memoryfree_mb"])
20 | total_swap_memory_mb = int(facts["swapsize_mb"])
21 |
22 | assert total_memory_mb >= (4 * 1024)
23 | assert total_memory_mb <= (128 * 1024)
24 | assert total_free_memory_mb <= total_memory_mb
25 | assert total_swap_memory_mb == total_memory_mb
26 |
27 |
28 | def test_add_specific_memory():
29 | """Get facts for specific memory."""
30 | facts = add_memory_info(count=32)
31 | total_memory_mb = int(facts["memorysize_mb"])
32 | total_free_memory_mb = int(facts["memoryfree_mb"])
33 | total_swap_memory_mb = int(facts["swapsize_mb"])
34 |
35 | assert total_memory_mb == (32 * 1024)
36 | assert total_free_memory_mb <= total_memory_mb
37 | assert total_swap_memory_mb == total_memory_mb
38 |
39 |
40 | def test_add_zero_memory():
41 | """Cannot add zero memory."""
42 | with pytest.raises(ValueError):
43 | add_memory_info(count=0)
44 |
45 |
46 | def test_add_negative_memory():
47 | """Cannot add negative memory."""
48 | with pytest.raises(ValueError):
49 | add_memory_info(count=-1)
50 |
51 |
52 | # Network
53 | def test_add_network_devices():
54 | """Get facts for network devices."""
55 | facts = add_network_devices()
56 | assert facts["network_lo"] == "127.0.0.0"
57 |
58 |
59 | # Operating Systems
60 | def test_add_random_operating_system():
61 | """Get facts for a random operating system."""
62 | facts = add_operating_system()
63 | assert facts["operatingsystem"]
64 | assert facts["osfamily"]
65 | assert facts["os"]["release"]["major"] >= 0
66 | assert facts["os"]["release"]["major"] <= 9
67 | assert facts["os"]["release"]["minor"] >= 0
68 | assert facts["os"]["release"]["minor"] <= 9
69 |
70 |
71 | # Operating Systems
72 | def test_add_random_operating_system_with_attributes():
73 | """Get facts for a random operating system with all attributes."""
74 | facts = add_operating_system(name="Fedora", family="Red Hat", major=25, minor=1)
75 | assert facts["operatingsystem"] == "Fedora"
76 | assert facts["osfamily"] == "Red Hat"
77 | assert facts["os"]["release"]["major"] == 25
78 | assert facts["os"]["release"]["minor"] == 1
79 |
80 |
81 | # Partitions
82 | def test_add_single_partition():
83 | """Get facts for a single partition."""
84 | facts = add_partitions()
85 | assert "sda1" in facts["partitions"].keys()
86 |
87 |
88 | def test_add_three_partitions():
89 | """Get facts for three partition."""
90 | facts = add_partitions(extra_partitions=3)
91 | assert "sda1" in facts["partitions"].keys()
92 | assert "sdb1" in facts["partitions"].keys()
93 | assert "sdb2" in facts["partitions"].keys()
94 | assert "sdb3" in facts["partitions"].keys()
95 |
96 |
97 | def test_add_zero_extra_partition():
98 | """Cannot add zero extra partitions."""
99 | with pytest.raises(ValueError):
100 | add_partitions(extra_partitions=0)
101 |
102 |
103 | def test_add_negative_extra_partition():
104 | """Cannot add negative extra partitions."""
105 | with pytest.raises(ValueError):
106 | add_partitions(extra_partitions=-1)
107 |
108 |
109 | # Processors
110 | def test_add_random_processors():
111 | """Get facts for random number of processors."""
112 | facts = add_processor_info()
113 | assert facts["processorcount"] >= 2
114 | assert facts["processorcount"] <= 16
115 | assert len(facts["processors"]["models"]) >= 2
116 | assert len(facts["processors"]["models"]) <= 16
117 |
118 |
119 | def test_add_one_processor():
120 | """Get facts for a single processor."""
121 | facts = add_processor_info(count=1)
122 | assert facts["processorcount"] == 1
123 | assert len(facts["processors"]["models"]) == 1
124 |
125 |
126 | def test_add_two_processors():
127 | """Get facts for two processors."""
128 | facts = add_processor_info(count=2)
129 | assert facts["processorcount"] == 2
130 | assert len(facts["processors"]["models"]) == 2
131 |
132 |
133 | def test_add_zero_processor():
134 | """Cannot add zero processors."""
135 | with pytest.raises(ValueError):
136 | add_processor_info(count=0)
137 |
138 |
139 | def test_add_negative_processor():
140 | """Cannot add negative processors."""
141 | with pytest.raises(ValueError):
142 | add_processor_info(count=-1)
143 |
--------------------------------------------------------------------------------
/tests/test_time.py:
--------------------------------------------------------------------------------
1 | """Tests for Time generator."""
2 |
3 | import datetime
4 |
5 | from fauxfactory import gen_time
6 |
7 |
8 | def test_gen_uuid_1():
9 | """Create a random UUID value."""
10 | for _ in range(100):
11 | assert isinstance(gen_time(), datetime.time)
12 |
--------------------------------------------------------------------------------
/tests/test_urls.py:
--------------------------------------------------------------------------------
1 | """Tests for URL generator."""
2 |
3 | import pytest
4 |
5 | from fauxfactory import (
6 | gen_alpha,
7 | gen_alphanumeric,
8 | gen_cjk,
9 | gen_numeric_string,
10 | gen_url,
11 | )
12 | from fauxfactory.constants import SCHEMES
13 |
14 |
15 | def test_gen_url_1():
16 | """Create a random URL."""
17 | for _ in range(10):
18 | result = gen_url()
19 | assert result
20 | assert result.split(":")[0] in SCHEMES
21 |
22 |
23 | def test_gen_url_2():
24 | """Create a random URL with http scheme."""
25 | for _ in range(10):
26 | result = gen_url(scheme="http")
27 | assert result
28 | assert result.split(":")[0] == "http"
29 |
30 |
31 | def test_gen_url_3():
32 | """Create a random URL with https scheme."""
33 | for _ in range(10):
34 | result = gen_url(scheme="https")
35 | assert result
36 | assert result.split(":")[0] == "https"
37 |
38 |
39 | def test_gen_url_4():
40 | """Create a random URL with ftp scheme."""
41 | for _ in range(10):
42 | result = gen_url(scheme="ftp")
43 | assert result
44 | assert result.split(":")[0] == "ftp"
45 |
46 |
47 | def test_gen_url_5():
48 | """Create a random URL with invalid scheme."""
49 | for _ in range(10):
50 | scheme = gen_alphanumeric()
51 | with pytest.raises(ValueError):
52 | gen_url(scheme=scheme)
53 |
54 |
55 | def test_gen_url_6():
56 | """Create a random URL with valid subdomain."""
57 | for _ in range(10):
58 | subdomain = gen_alphanumeric()
59 | result = gen_url(subdomain=subdomain)
60 | assert result
61 |
62 | # Breakdown the generated URL
63 | scheme_breakdown = result.split("//")
64 | domain = scheme_breakdown[1].split(".")
65 | assert domain[0] == subdomain
66 |
67 |
68 | def test_gen_url_7():
69 | """Create a random URL with empty subdomain."""
70 | result = gen_url(subdomain="")
71 | assert result
72 |
73 |
74 | def test_gen_url_8():
75 | """Create a random URL with whitespace subdomain."""
76 | with pytest.raises(ValueError):
77 | gen_url(subdomain=" ")
78 |
79 |
80 | def test_gen_url_9():
81 | """Create a random URL with invalid subdomain."""
82 | for _ in range(10):
83 | subdomain = gen_cjk()
84 | with pytest.raises(ValueError):
85 | gen_url(subdomain=subdomain)
86 |
87 |
88 | def test_gen_url_10():
89 | """Create a random URL with valid TLDS."""
90 | for _ in range(10):
91 | tlds = gen_alpha(length=3)
92 | result = gen_url(tlds=tlds)
93 | assert result
94 | assert result.split(".")[-1] == tlds
95 |
96 |
97 | def test_gen_url_11():
98 | """Create a random URL with numeric TLDS."""
99 | for _ in range(10):
100 | with pytest.raises(ValueError):
101 | tlds = gen_numeric_string(length=3)
102 | gen_url(tlds=tlds)
103 |
104 |
105 | def test_gen_url_12():
106 | """Create a random URL with whitespace TLDS."""
107 | for _ in range(10):
108 | with pytest.raises(ValueError):
109 | gen_url(tlds=" ")
110 |
--------------------------------------------------------------------------------
/tests/test_utils.py:
--------------------------------------------------------------------------------
1 | """Unittests for all methods found in `utils.py`."""
2 |
3 | import pytest
4 |
5 | from fauxfactory.helpers import is_positive_int
6 |
7 |
8 | @pytest.mark.parametrize("length", [1, 2, 3, 30, 100])
9 | def test_positive_value(length):
10 | """Positive values are allowed."""
11 | assert is_positive_int(length) is None
12 |
13 |
14 | @pytest.mark.parametrize("length", [-1, -2, -3, -30, -100])
15 | def test_negative_value(length):
16 | """Negative values are not allowed."""
17 | with pytest.raises(ValueError):
18 | is_positive_int(length)
19 |
20 |
21 | def test_zero_value():
22 | """Zero is not an allowed value."""
23 | with pytest.raises(ValueError):
24 | is_positive_int(0)
25 |
26 |
27 | def test_none_value():
28 | """None is not an allowed value."""
29 | with pytest.raises(ValueError):
30 | is_positive_int(None)
31 |
32 |
33 | def test_empty_value():
34 | """Empty list is not an allowed value."""
35 | with pytest.raises(ValueError):
36 | is_positive_int([])
37 |
38 |
39 | @pytest.mark.parametrize("length", ["a", "foo", " ", "1", "0", "-1"])
40 | def test_non_numeric_value(length):
41 | """Non-numeric values are not allowed."""
42 | with pytest.raises(ValueError):
43 | is_positive_int(length)
44 |
--------------------------------------------------------------------------------
/tests/test_uuids.py:
--------------------------------------------------------------------------------
1 | """Tests for UUID generator."""
2 |
3 | from fauxfactory import gen_uuid
4 |
5 |
6 | def test_gen_uuid_1():
7 | """Create a random UUID4 value."""
8 | for _ in range(100):
9 | assert gen_uuid()
10 |
--------------------------------------------------------------------------------