From 723e2b5ce9000399f4941c28ab03988da5f1f057 Mon Sep 17 00:00:00 2001 From: Ivan Beloborodov Date: Thu, 15 Dec 2016 12:10:02 +0300 Subject: [PATCH] support for testing via pytest Python source code generation via Sphynx --- .gitignore | 6 + README.md | 33 +- alembictests.ini | 36 +- develop-requirements.txt | 4 + development.ini | 58 +- lingvodoc/__init__.py | 12 +- lingvodoc/cache/caching.py | 5 +- lingvodoc/models.py | 8 +- lingvodoc/scripts/corpora_converter.py | 15 +- pyramid_autodoc.ini | 112 +++ setup.py | 2 +- sphinx/Makefile | 251 ++++++ sphinx/make.bat | 284 +++++++ sphinx/source/conf.py | 203 +++++ sphinx/source/index.rst | 41 + sphinx/source/rest_api.rst | 9 + tests/__init__.py | 23 + tests/common.py | 8 + tests/dictionary/tests_dictionary.py | 14 + tests/helper_methods/tests_helper_methods.py | 12 + .../lexical_entries/tests_lexical_entries.py | 13 + tests/merge/tests_merge.py | 9 + tests/perspective/tests_perspective.py | 14 + tests/test_real_dictionaries.py | 16 +- tests/tests.py | 89 +- tests/tests_language.py | 785 +++++++++--------- tox.ini | 11 +- 27 files changed, 1595 insertions(+), 478 deletions(-) create mode 100644 develop-requirements.txt create mode 100644 pyramid_autodoc.ini create mode 100644 sphinx/Makefile create mode 100644 sphinx/make.bat create mode 100644 sphinx/source/conf.py create mode 100644 sphinx/source/index.rst create mode 100644 sphinx/source/rest_api.rst diff --git a/.gitignore b/.gitignore index 6996ba5f8..478470341 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.cache .idea/ .virtual_env/ virtual_env/ @@ -19,3 +20,8 @@ alembic.ini # webui2 target/ + +Session.vim +pytest.output +sphinx/source/apidoc-*/ +sphinx/pyramid_autodoc diff --git a/README.md b/README.md index 6c015a6de..8681feb60 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ If you are using less recent distro version, replace `xenial` with `trusty` or ` * `effective_cache_size` - 1/8 of total RAM (e.g. 4096MB) * `wal_level = replica` * Restart postgres: `sudo service postgresql restart` - * Import the latest database backup (from-scratch creation look in `# from psql` section): `sudo -u posgres psql < lingvodoc.sql` + * Import the latest database backup (from-scratch creation look in `# from psql` section): `sudo -u postgres psql lingvodoc < lingvodoc.sql` 2. Install Redis: `sudo apt-get install redis-server`. 3. Install compilers, libraries and git: `sudo apt-get install build-essential python3-dev libssl-dev git` 4. Install venv-creator: `sudo apt-get install python3-virtualenv` @@ -164,3 +164,34 @@ API documentation /authors /sound /markup + +Testing +------- + +Testing is performed via [pytest](http://doc.pytest.org). Installation of required packages: +``` +pip install -r develop-requirements.txt +``` + +Running tests from the root project directory: +``` +$VENV/bin/py.test +``` + +Documentation +------------- + +Documentation for Python source code, including tests, can be generated via [Sphinx](http://www.sphinx-doc.org). Installation of required packages: +``` +pip install -r develop-requirements.txt +``` + +Generating documentation from the root project directory: +``` +make -f sphinx/Makefile html +``` + +Generated documentation can be accessed at `sphinx/build/html/index.html`. It includes all Python packages, modules, classes and functions of the project; descriptions of packages, modules, classes and functions are automatically produced from their docstrings. + +Documentation also includes an up-to-date list of Pyramid REST API routes provided by the application, extracted via [pyramid\_autodoc](https://github.com/SurveyMonkey/pyramid_autodoc) Sphinx extension. + diff --git a/alembictests.ini b/alembictests.ini index 9c7ae606c..cbabd0967 100644 --- a/alembictests.ini +++ b/alembictests.ini @@ -7,7 +7,7 @@ # path to migration scripts script_location = alembic -sqlalchemy.url = postgresql+psycopg2://postgres:@localhost/lingvodoc_testing +sqlalchemy.url = postgresql+psycopg2://postgres@/lingvodoc_testing ;sqlalchemy.url = sqlite:////home/student/projects/lingvodoc/lingvodoc_testing.sqlite ;sqlalchemy.url = sqlite:///lingvodoc_testing.sqlite @@ -50,7 +50,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = postgresql+psycopg2://postgres:@localhost/lingvodoc_testing +sqlalchemy.url = postgresql+psycopg2://postgres@/lingvodoc_testing ;sqlalchemy.url = sqlite:////home/student/projects/lingvodoc/lingvodoc_testing.sqlite ;sqlalchemy.url = sqlite:///lingvodoc_testing.sqlite @@ -63,15 +63,15 @@ sqlalchemy.url = postgresql+psycopg2://postgres:@localhost/lingvodoc_testing ### [server:main] -;use = egg:waitress#main -use = egg:gunicorn#main -workers = 3 -timeout = 3000 -proc_name = lingvodoc -bind = "0.0.0.0:6543" +use = egg:waitress#main +;use = egg:gunicorn#main +;workers = 3 +;timeout = 3000 +;proc_name = lingvodoc +;bind = "0.0.0.0:6543" host = 0.0.0.0 port = 6543 -max_request_body_size = 2147483648 +;max_request_body_size = 2147483648 ### # logging configuration @@ -154,17 +154,17 @@ no-orphans = true log-slow = true -virtualenv = /Users/al/environments/lingvodocenv/ +#virtualenv = /Users/al/environments/lingvodocenv/ callable = lingvodoc -[cache:dogpile] -backend = dogpile.cache.redis +#[cache:dogpile] +#backend = dogpile.cache.redis -[cache:dogpile:args] -host: localhost -port: 6379 -db: 0 -redis_expiration_time: 60 -distributed_lock: True \ No newline at end of file +#[cache:dogpile:args] +#host: localhost +#port: 6379 +#db: 0 +#redis_expiration_time: 60 +#distributed_lock: True diff --git a/develop-requirements.txt b/develop-requirements.txt new file mode 100644 index 000000000..486f9d1b5 --- /dev/null +++ b/develop-requirements.txt @@ -0,0 +1,4 @@ +Sphinx +pytest +simplejson +webtest diff --git a/development.ini b/development.ini index 69ff0944b..09c016c0e 100644 --- a/development.ini +++ b/development.ini @@ -6,6 +6,8 @@ [app:main] use = egg:lingvodoc +secret = 'secret string' + pyramid.reload_templates = true pyramid.debug_authorization = false pyramid.debug_notfound = false @@ -15,7 +17,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/lingvodoc.sqlite +sqlalchemy.url = postgresql+psycopg2://postgres@/lingvodoc # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. @@ -45,7 +47,7 @@ keys = console keys = generic [logger_root] -level = INFO +level = DEBUG handlers = console [logger_lingvodoc] @@ -78,21 +80,37 @@ administrator_password = password [backend:storage] # disk or openstack -storagetype = disk -path = /tmp -authurl = http://10.10.10.121:5000/v2.0 -store = http://adelaide.intra.ispras.ru/horizon/project/containers -user = admin -key = tester -auth_version = 2.0 -tenant_name = admin - -[cache:dogpile] -backend = dogpile.cache.redis - -[cache:dogpile:args] -host: localhost -port: 6379 -db: 0 -redis_expiration_time: 60 -distributed_lock: True +type = disk +path = /tmp/ +prefix = http://localhost:6543/ +static_route = objects/ +#authurl = http://10.10.10.121:5000/v2.0 +#store = http://adelaide.intra.ispras.ru/horizon/project/containers +#user = admin +#key = tester +#auth_version = 2.0 +#tenant_name = admin + +[uwsgi] +socket = 0.0.0.0:6543 +protocol = http +master = true + +processes = 4 + +harakiri = 60 +harakiri-verbose = true +limit-post = 65536 +post-buffering = 8192 + +listen = 256 + +max-requests = 1000 + +reload-on-as = 128 +reload-on-rss = 96 +no-orphans = true + +log-slow = true + +callable = lingvodoc diff --git a/lingvodoc/__init__.py b/lingvodoc/__init__.py index 106a3a6e8..f4803e5d1 100755 --- a/lingvodoc/__init__.py +++ b/lingvodoc/__init__.py @@ -24,6 +24,7 @@ def configure_routes(config): """ This function registers views from .views for pyramid event loop. Actually all listed items here is our 'site-map' for: + 1) web-views (html+javascript) - will be marked as 'web-view' 2) REST API - will be marked as 'API' 3) internal calls for frontend (in most cases it's API but not always). If it's not API part, will be marked @@ -675,15 +676,18 @@ def main(global_config, **settings): config_file = global_config['__file__'] parser = ConfigParser() parser.read(config_file) + # TODO: DANGER - storage = dict() - for k, v in parser.items('backend:storage'): - storage[k] = v - settings['storage'] = storage + + settings['storage'] = dict(parser.items( + 'backend:storage' if parser.has_section('backend:storage') else + 'storage')) + if parser.has_section('app:desktop'): for k, v in parser.items('app:desktop'): storage[k] = v settings['desktop'] = storage + config = Configurator(settings=settings) log = logging.getLogger(__name__) diff --git a/lingvodoc/cache/caching.py b/lingvodoc/cache/caching.py index dca0b42fa..c03773dff 100644 --- a/lingvodoc/cache/caching.py +++ b/lingvodoc/cache/caching.py @@ -5,7 +5,9 @@ from lingvodoc.cache.mock.cache import MockCache -MEMOIZE = None +# We initialize MEMOIZE to identity function so that if the cache is not initialized (e.g. when an +# automatically extracted source code documentation is being compiled), it is still possible to use it. +MEMOIZE = lambda x: x CACHE = None @@ -52,3 +54,4 @@ def initialize_cache(args): region = make_region().configure(**args) MEMOIZE = cache_responses(region) CACHE = CommonCache(region) + diff --git a/lingvodoc/models.py b/lingvodoc/models.py index a7f4bf8d6..3127f0aa0 100755 --- a/lingvodoc/models.py +++ b/lingvodoc/models.py @@ -590,12 +590,14 @@ class Field(CompositeIdMixin, AdditionalMetadataMixin): """ With this objects we specify allowed fields for dictionary perspective. This class is used for three purposes: + 1. To control final web-page view. With it we know which fields belong to perspective (and what we should - show on dictionary page. + show on dictionary page. 2. Also we can know what entities should be grouped under the buttons (for example paradigms). Also we can - control connections between level-one and level-two entities. And we can control grouping entities (if we - want to have not only etymology connections). + control connections between level-one and level-two entities. And we can control grouping entities (if we + want to have not only etymology connections). 3. With it we can restrict to use any entity types except listed here (security concerns). + Parent: DictionaryPerspective. """ marked_for_deletion = Column(Boolean, default=False, nullable=False) diff --git a/lingvodoc/scripts/corpora_converter.py b/lingvodoc/scripts/corpora_converter.py index 576f2580b..bbf1ccd4b 100644 --- a/lingvodoc/scripts/corpora_converter.py +++ b/lingvodoc/scripts/corpora_converter.py @@ -130,12 +130,13 @@ def parse_word(self, word): #----------------------------------------------------------------------- -element_tree = ElementTree.parse('corpus.xml') - -with open('corpus.json', 'w') as corpus_file: - simplejson.dump( - Corpus().parse_document(element_tree.getroot()), - corpus_file, - ensure_ascii=False, separators=(',', ':'), sort_keys = False) +if __name__ == '__main__': + element_tree = ElementTree.parse('corpus.xml') + + with open('corpus.json', 'w') as corpus_file: + simplejson.dump( + Corpus().parse_document(element_tree.getroot()), + corpus_file, + ensure_ascii=False, separators=(',', ':'), sort_keys = False) #----------------------------------------------------------------------- diff --git a/pyramid_autodoc.ini b/pyramid_autodoc.ini new file mode 100644 index 000000000..802fb8f16 --- /dev/null +++ b/pyramid_autodoc.ini @@ -0,0 +1,112 @@ +# +# Pyramid configuration used for automaric generation of REST API documentation. +# Copied from development.ini and then slightly modified. +# + +[app:main] +use = egg:lingvodoc + +secret = 'secret string' + +pyramid.reload_templates = true +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_debugtoolbar + pyramid_tm + +sqlalchemy.url = postgresql+psycopg2://postgres@/lingvodoc + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html +### + +[loggers] +keys = root, lingvodoc, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = DEBUG +handlers = console + +[logger_lingvodoc] +level = DEBUG +handlers = +qualname = lingvodoc + +[logger_sqlalchemy] +level = DEBUG +handlers = +qualname = sqlalchemy.engine +# "level = INFO" logs SQL queries. +# "level = DEBUG" logs SQL queries and results. +# "level = WARN" logs neither. (Recommended for production systems.) + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s + +[app:accounts] +use = egg:lingvodoc +# no emphasis or special symbols should be used. +administrator_login = admin +administrator_password = password + +[storage] +# disk or openstack +type = disk +path = /tmp/ +prefix = http://localhost:6543/ +static_route = objects/ +#authurl = http://10.10.10.121:5000/v2.0 +#store = http://adelaide.intra.ispras.ru/horizon/project/containers +#user = admin +#key = tester +#auth_version = 2.0 +#tenant_name = admin + +[uwsgi] +socket = 0.0.0.0:6543 +protocol = http +master = true + +processes = 4 + +harakiri = 60 +harakiri-verbose = true +limit-post = 65536 +post-buffering = 8192 + +listen = 256 + +max-requests = 1000 + +reload-on-as = 128 +reload-on-rss = 96 +no-orphans = true + +log-slow = true + +callable = lingvodoc diff --git a/setup.py b/setup.py index 560f742fa..2d6199b62 100644 --- a/setup.py +++ b/setup.py @@ -37,4 +37,4 @@ initialize_lingvodoc_db = lingvodoc.scripts.initializedb:main """, ) -print(find_packages()) \ No newline at end of file +print(find_packages()) diff --git a/sphinx/Makefile b/sphinx/Makefile new file mode 100644 index 000000000..0f7d9fb16 --- /dev/null +++ b/sphinx/Makefile @@ -0,0 +1,251 @@ +# Makefile for Sphinx documentation +# + +sphinx_dir := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) +lingvodoc_dir := $(realpath $(sphinx_dir)/..) + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = $(sphinx_dir)/build + +# Internal variables. +PAPEROPT_a4 = -D latex_elements.papersize=a4 +PAPEROPT_letter = -D latex_elements.papersize=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(sphinx_dir)/source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(sphinx_dir)/source + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and an HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " lualatexpdf to make LaTeX files and run them through lualatex" + @echo " xelatexpdf to make LaTeX files and run them through xelatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +# Slightly patched pyramid_autodoc which allows to avoid some subtle errors on the current codebase. +$(sphinx_dir)/pyramid_autodoc: + cd $(sphinx_dir) && git clone https://github.com/diefans/pyramid_autodoc.git + pip install $(sphinx_dir)/pyramid_autodoc + +.PHONY: html +html: | $(sphinx_dir)/pyramid_autodoc + sphinx-apidoc -M --force -o $(sphinx_dir)/source/apidoc-lingvodoc $(lingvodoc_dir)/lingvodoc + sphinx-apidoc -M --force -o $(sphinx_dir)/source/apidoc-tests $(lingvodoc_dir)/tests + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Lingvodoc.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Lingvodoc.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Lingvodoc" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Lingvodoc" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: lualatexpdf +lualatexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through lualatex..." + $(MAKE) PDFLATEX=lualatex -C $(BUILDDIR)/latex all-pdf + @echo "lualatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: xelatexpdf +xelatexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through xelatex..." + $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf + @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/sphinx/make.bat b/sphinx/make.bat new file mode 100644 index 000000000..0a338d652 --- /dev/null +++ b/sphinx/make.bat @@ -0,0 +1,284 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +pushd %~dp0 + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +set I18NSPHINXOPTS=%SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and an HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. epub3 to make an epub3 + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + echo. dummy to check syntax errors of document sources + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Lingvodoc.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Lingvodoc.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +if "%1" == "dummy" ( + %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. Dummy builder generates no files. + goto end +) + +:end +popd diff --git a/sphinx/source/conf.py b/sphinx/source/conf.py new file mode 100644 index 000000000..575dfff1c --- /dev/null +++ b/sphinx/source/conf.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Lingvodoc documentation build configuration file, created by +# sphinx-quickstart on Thu Dec 15 08:11:36 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +import os +import sys +#sys.path.insert(0, os.path.abspath('../../lingvodoc')) +sys.path.insert(0, os.path.abspath('../..')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'pyramid_autodoc', + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'Lingvodoc' +author = 'Oleg Borisenko' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.0b1' +# The full version, including alpha/beta/rc tags. +release = '2.0b1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# Alabaster options: https://alabaster.readthedocs.io/en/latest/ +# customization.html#theme-options. +# +html_theme_options = { + 'page_width': '1240px', # default 940px. + 'sidebar_width': '320px', # default 220px. +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Lingvodoc-documentation' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Lingvodoc.tex', 'Lingvodoc Documentation', + 'Oleg Borisenko', 'manual'), +] + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'lingvodoc', 'Lingvodoc Documentation', + [author], 1) +] + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Lingvodoc', 'Lingvodoc Documentation', + author, 'Lingvodoc', 'One line description of project.', + 'Miscellaneous'), +] + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} + +# -- Additional options ------------------------------------------------ + +autosummary_generate = True + +#: Showing autodoc'ed module members in order they appear in the source +#: code. +autodoc_member_order = 'bysource' + +autodoc_default_flags = [ + 'members', + 'private-members', + 'show-inheritance', + 'undoc-members'] + +def skip(app, what, name, obj, skip, options): + """ + Skipping callback which does not skip '__init__'. + """ + + if name == "__init__": + return False + + return skip + +# Disabling skipping of __init__ in autodoc-generated documentation. See +# answer of the question +# "How to use Sphinx's autodoc to document a class's __init__(self) +# method?" . +# +def setup(app): + app.connect("autodoc-skip-member", skip) + +# ---------------------------------------------------------------------- diff --git a/sphinx/source/index.rst b/sphinx/source/index.rst new file mode 100644 index 000000000..2a9788f46 --- /dev/null +++ b/sphinx/source/index.rst @@ -0,0 +1,41 @@ + +.. Lingvodoc documentation master file, created by + sphinx-quickstart on Thu Dec 15 08:11:36 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Lingvodoc's documentation! +===================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + +| + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +| + +Packages +======== + +.. autosummary:: + lingvodoc + tests + +| + +Pyramid's REST API +================== + +.. toctree:: + :maxdepth: 1 + + rest_api + diff --git a/sphinx/source/rest_api.rst b/sphinx/source/rest_api.rst new file mode 100644 index 000000000..5438a2a20 --- /dev/null +++ b/sphinx/source/rest_api.rst @@ -0,0 +1,9 @@ + +Pyramid's REST API +================== + +| + +.. autopyramid:: pyramid_autodoc.ini + :format: httpdomain + diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb..1906e1a1e 100755 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,23 @@ +# +# How tests are organized and how they should work +# +# Tests should be run with pytest, with current configuration (see tox.ini file) it is enough to run +# '$VENV/bin/py.test' from the lingvodoc's root directory. +# +# We have tests from the previous version, and we should ultimately have functional tests for each REST API +# request (see lingvodoc/__init__.py file for supported APIs). +# +# Each REST API functional test should clearly identify API it tests, e.g. by mentioning its name in a +# comment. +# +# Tests from the previous version that are not yet modified to work with the current one are marked with +# pytest's skip markers (see http://doc.pytest.org/en/latest/skipping.html). Until all tests from the +# previous version are converted, before creating a new API test please check if there is an unconverted +# test of this API from the previous version, and, if indeed there is, convert it instead of creating a new +# one. +# + +""" +Various tests for the Lingvodoc's Python source code. +""" + diff --git a/tests/common.py b/tests/common.py index 33699a345..29f1db4ff 100644 --- a/tests/common.py +++ b/tests/common.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + import json import os diff --git a/tests/dictionary/tests_dictionary.py b/tests/dictionary/tests_dictionary.py index 16351c14a..cdca48bdc 100644 --- a/tests/dictionary/tests_dictionary.py +++ b/tests/dictionary/tests_dictionary.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from tests.common import initValuesFactory from tests.common import load_correct_answers @@ -13,7 +21,10 @@ HTTPForbidden ) +import pytest + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class NewTestClass(MyTestCase): def testlogin(self): @@ -26,6 +37,7 @@ def testlogin(self): self.assertDictEqual(response.json, correct_answer, stop_words=['id', 'signup_date']) +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class DictionaryTest(MyTestCase): def setUp(self): @@ -196,6 +208,7 @@ def testDictionaryInfo(self): self.assertEqual(response.json, correct_answers[test_name]) +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class ConvertedDictionaryTest(MyTestCase): def test_dict_convert(self): @@ -263,3 +276,4 @@ def test_dict_convert(self): json_file = open('dictionary/test_dict_convert.json', 'r') correct_answer = json.loads(json_file.read()) self.assertDictEqual(response.json, correct_answer, set_like= True) + diff --git a/tests/helper_methods/tests_helper_methods.py b/tests/helper_methods/tests_helper_methods.py index fd7c5c21c..4a4adaf32 100644 --- a/tests/helper_methods/tests_helper_methods.py +++ b/tests/helper_methods/tests_helper_methods.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from pyramid.httpexceptions import ( @@ -12,12 +20,15 @@ ) import json +import pytest + def func_name(): import traceback return traceback.extract_stack(None, 2)[0][2] +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class TestHelperMethods(MyTestCase): def testsignup(self): @@ -219,3 +230,4 @@ def test_dict_convert_method(self): 'object_id', 'parent_client_id', 'parent_object_id'], set_like= True) + diff --git a/tests/lexical_entries/tests_lexical_entries.py b/tests/lexical_entries/tests_lexical_entries.py index 3ab469235..767c79601 100644 --- a/tests/lexical_entries/tests_lexical_entries.py +++ b/tests/lexical_entries/tests_lexical_entries.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from tests.common import initValuesFactory from tests.common import load_correct_answers @@ -17,6 +25,10 @@ HTTPForbidden ) +import pytest + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class LexicalEntriesTest(MyTestCase): def setUp(self): @@ -406,3 +418,4 @@ def testApproveEntityAll(self): self.assertEqual(response.status_int, HTTPOk.code) # print('correct:', response.json) self.assertEqual(response.json, correct_answers[test_name]) + diff --git a/tests/merge/tests_merge.py b/tests/merge/tests_merge.py index 945fccc19..086ba67a1 100644 --- a/tests/merge/tests_merge.py +++ b/tests/merge/tests_merge.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from tests.common import initValuesFactory from tests.common import load_correct_answers @@ -13,6 +21,7 @@ HTTPForbidden ) + class MergeTest(MyTestCase): def _create_sample_dict(self, language): diff --git a/tests/perspective/tests_perspective.py b/tests/perspective/tests_perspective.py index c2e967d12..ad75d7ccc 100644 --- a/tests/perspective/tests_perspective.py +++ b/tests/perspective/tests_perspective.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from tests.common import initValuesFactory from tests.common import load_correct_answers @@ -13,7 +21,12 @@ HTTPForbidden ) +import pytest + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class PerspectiveTest(MyTestCase): + def _build_ordered_lists(self, response, correct_answer): self.assertEqual(response.status_int, HTTPOk.code) answer = sorted(correct_answer, key=lambda x: (x['client_id'], x['object_id'])) @@ -290,3 +303,4 @@ def testPerspectiveInfo(self): (dict_1['client_id'], dict_1['object_id'], persp_1['client_id'], persp_1['object_id'])) self.assertEqual(response.status_int, HTTPOk.code) self.assertEqual(response.json, correct_answers[test_name]) + diff --git a/tests/test_real_dictionaries.py b/tests/test_real_dictionaries.py index 3d77ab986..16f14cd14 100644 --- a/tests/test_real_dictionaries.py +++ b/tests/test_real_dictionaries.py @@ -1,3 +1,11 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + from tests.tests import MyTestCase from pyramid.httpexceptions import ( @@ -12,13 +20,14 @@ ) import threading -from tests.tests import alembicini +from .tests import alembic_ini_path from pyramid import paster from waitress import serve import json + def pserve(): - myapp = paster.get_app('../' + alembicini) + myapp = paster.get_app(alembic_ini_path) def my_serve(): @@ -34,4 +43,5 @@ def my_serve(): class ConvertTest(MyTestCase): - pass \ No newline at end of file + pass + diff --git a/tests/tests.py b/tests/tests.py index cac192229..7c7208493 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,3 +1,10 @@ +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + import unittest import transaction @@ -22,13 +29,24 @@ from subprocess import PIPE, Popen from configparser import ConfigParser -alembicini = 'alembictests.ini' +import os +import pdb +import pytest +import sys + + +# Assuming that required .ini-file is in the parent directory of the +# 'tests' package --- i.e., package of this module. +alembic_ini_path = os.path.join( + os.path.dirname(__file__), '..', 'alembictests.ini') + parser = ConfigParser() -parser.read('../' + alembicini) +parser.read(alembic_ini_path) alembic_conf = dict() for k, v in parser.items('alembic'): alembic_conf[k] = v dbname = alembic_conf['sqlalchemy.url'] + from lingvodoc.scripts.initializedb import data_init @@ -37,8 +55,6 @@ def debug_print(debug_flag, mssg): for entry in mssg: print(entry) -# from copy import deepcopy - def new_dict(d, key_set, stop_words=list(), debug_flag=False): new_d = dict() @@ -111,6 +127,9 @@ def shutdown(self=None): # that is really bad. really class MyTestCase(unittest.TestCase): + """ + Common parent class for Lingvodoc API test cases. + """ server_is_up = False @@ -123,45 +142,46 @@ def get_server_is_up(cls): return MyTestCase.server_is_up def setUp(self): - # try: - import os - self.config = testing.setUp() - import webtest.http - from pyramid import paster - from sqlalchemy import create_engine - engine = create_engine(dbname) - - myapp = paster.get_app('../' + alembicini) - if not self.get_server_is_up(): - self.ws = webtest.http.StopableWSGIServer.create(myapp, port=6543, host="0.0.0.0") # todo: change to pserve - self.ws.wait() - self.set_server_is_up(True) - self.app = webtest.TestApp(myapp) - # DBSession.remove() - # bashcommand = "alembic -c %s downgrade base" % alembicini - DBSession.configure(bind=engine) - bashcommand = "alembic -c %s upgrade head" % alembicini - args = bashcommand.split() - pathdir = os.path.dirname(os.path.realpath(__file__)) - pathdir = pathdir[:(len(pathdir) - 6)] - my_env = os.environ - proc = Popen(args, cwd=pathdir, env=my_env) - proc.communicate() - accounts = get_appsettings('../' + alembicini, 'accounts') - data_init(transaction.manager, accounts) - # except: - # self.tearDown() + + self.config = testing.setUp() + + import webtest.http + from pyramid import paster + from sqlalchemy import create_engine + engine = create_engine(dbname) + + myapp = paster.get_app(alembic_ini_path) + if not self.get_server_is_up(): + self.ws = webtest.http.StopableWSGIServer.create(myapp, port=6543, host="0.0.0.0") # todo: change to pserve + self.ws.wait() + self.set_server_is_up(True) + self.app = webtest.TestApp(myapp) + + DBSession.configure(bind=engine) + bashcommand = "alembic -c %s upgrade head" % alembic_ini_path + + args = bashcommand.split() + pathdir = os.path.dirname(os.path.realpath(__file__)) + pathdir = pathdir[:(len(pathdir) - 6)] + my_env = os.environ + proc = Popen(args, cwd=pathdir, env=my_env) + proc.communicate() + + accounts = get_appsettings(alembic_ini_path, 'accounts') + data_init(transaction.manager, accounts) def tearDown(self): - import os + DBSession.remove() - bashcommand = "alembic -c %s downgrade base" % alembicini + + bashcommand = "alembic -c %s downgrade base" % alembic_ini_path args = bashcommand.split() pathdir = os.path.dirname(os.path.realpath(__file__)) pathdir = pathdir[:(len(pathdir) - 6)] my_env = os.environ proc = Popen(args, cwd=pathdir, env=my_env) proc.communicate() + testing.tearDown() def assertEqual(self, d1, d2, msg=None, stop_words=list(), set_like=True, debug_flag=False): @@ -318,6 +338,7 @@ def dict_convert(self, filename='test.sqlite', user_id=None): return dict_ids, persp_ids +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') class TestBig(MyTestCase): def one_big_test(self): diff --git a/tests/tests_language.py b/tests/tests_language.py index dcef4c78f..3fdba96d4 100644 --- a/tests/tests_language.py +++ b/tests/tests_language.py @@ -1,384 +1,401 @@ -# import unittest -# import transaction -# -# from pyramid import testing -# -# from lingvodoc.models import DBSession -# from pyramid.httpexceptions import HTTPNotFound, HTTPOk, HTTPBadRequest, HTTPConflict, HTTPInternalServerError -# -# -# class TestViewLanguageSuccessCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# from lingvodoc.models import ( -# Base, -# Language, -# UserEntitiesTranslationString, -# Locale -# ) -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# with transaction.manager: -# ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") -# DBSession.add(ru_locale) -# DBSession.flush() -# new_uets = UserEntitiesTranslationString(object_id = 1, client_id = 1, locale_id=1, -# translation_string = 'test', translation = 'working') -# DBSession.add(new_uets) -# new_lang=Language(client_id=1, object_id=1, translation_string = 'test') -# DBSession.add(new_lang) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_view_language(self): -# from lingvodoc.views import view_language -# request = testing.DummyRequest() -# request.matchdict['client_id'] = 1 -# request.matchdict['object_id'] = 1 -# response = view_language(request) -# self.assertEqual(response['status'], HTTPOk.code) -# self.assertEqual(response['translation_string'], 'working') -# -# -# class TestViewLanguageFailureCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# from lingvodoc.models import ( -# Base -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_view_language(self): -# from lingvodoc.views import view_language -# request = testing.DummyRequest() -# request.matchdict['client_id'] = 42 -# request.matchdict['object_id'] = 42 -# response = view_language(request) -# self.assertEqual(response['status'], HTTPNotFound.code) -# -# -# class TestEditLanguageSuccessCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# import webtest -# from pyramid import paster -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# myapp = paster.get_app('testing.ini') -# self.app = webtest.TestApp(myapp) -# from lingvodoc.models import ( -# Base, -# Language, -# Locale, -# UserEntitiesTranslationString, -# User, -# Passhash, -# Client -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# with transaction.manager: -# ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") -# DBSession.add(ru_locale) -# en_locale = Locale(id=2, shortcut="en", intl_name="English") -# DBSession.add(en_locale) -# DBSession.flush() -# new_user = User(id=1, login='test', default_locale_id = 1) -# new_pass = Passhash(password='pass') -# DBSession.add(new_pass) -# new_user.password = new_pass -# DBSession.add(new_user) -# new_client = Client(id=1, user=new_user) -# DBSession.add(new_client) -# DBSession.flush() -# new_uets = UserEntitiesTranslationString(object_id = 1, client_id = 1, locale_id=1, -# translation_string = 'test', translation = 'not working') -# DBSession.add(new_uets) -# new_lang = Language(client_id=1, object_id=1, translation_string='test') -# DBSession.add(new_lang) -# new_lang = Language(client_id=1, object_id=2, translation_string='testy') -# DBSession.add(new_lang) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_edit_language_name(self): -# from lingvodoc.models import ( -# Language, -# UserEntitiesTranslationString -# ) -# response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) -# response = self.app.put_json('/language/1/1', params={'translation_string': 'test', 'translation': 'working'}) -# self.assertEqual(response.status_int, HTTPOk.code) -# language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() -# self.assertNotEqual(language, None) -# uets = DBSession.query(UserEntitiesTranslationString).\ -# filter_by(translation_string=language.translation_string, locale_id=1).first() -# self.assertNotEqual(uets, None) -# self.assertEqual(uets.translation, 'working') -# -# def test_edit_language_parent(self): -# from lingvodoc.models import ( -# Language -# ) -# response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) -# response = self.app.put_json('/language/1/1', params={'parent_object_id': 2, 'parent_client_id': 1}) -# self.assertEqual(response.status_int, HTTPOk.code) -# language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() -# self.assertNotEqual(language, None) -# parent = DBSession.query(Language).filter_by(client_id=1, object_id=2).first() -# self.assertNotEqual(parent, None) -# self.assertEqual(language.parent, parent) -# -# -# class TestEditLanguageFailureCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# import webtest -# from pyramid import paster -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# myapp = paster.get_app('testing.ini') -# self.app = webtest.TestApp(myapp) -# from lingvodoc.models import ( -# Base, -# Locale, -# User, -# Passhash, -# Client -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# with transaction.manager: -# ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") -# DBSession.add(ru_locale) -# en_locale = Locale(id=2, shortcut="en", intl_name="English") -# DBSession.add(en_locale) -# DBSession.flush() -# new_user = User(id=1, login='test', default_locale_id = 1) -# new_pass = Passhash(password='pass') -# DBSession.add(new_pass) -# new_user.password = new_pass -# DBSession.add(new_user) -# new_client = Client(id=1, user=new_user) -# DBSession.add(new_client) -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_edit_language_without_login(self): -# response = self.app.put_json('/language/42/42', -# params={'translation_string': 'imastring', 'translation': 'imatranslation'}, -# status = HTTPBadRequest.code) -# self.assertEqual(response.status_int, HTTPBadRequest.code) -# -# def test_edit_language_with_login(self): -# response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) -# response = self.app.put_json('/language/42/42', -# params={'translation_string': 'imastring', 'translation': 'imatranslation'}, -# status = HTTPNotFound.code) -# self.assertEqual(response.status_int, HTTPNotFound.code) -# -# -# class TestDeleteLanguageSuccessCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# from lingvodoc.models import ( -# Base, -# Language -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# with transaction.manager: -# new_lang = Language(client_id=1, object_id=1, translation_string='test') -# DBSession.add(new_lang) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_delete_language(self): -# from lingvodoc.views import delete_language -# from lingvodoc.models import ( -# Language -# ) -# request = testing.DummyRequest() -# request.matchdict['client_id'] = 1 -# request.matchdict['object_id'] = 1 -# response = delete_language(request) -# -# self.assertEqual(response['status'], HTTPOk.code) -# language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() -# self.assertNotEqual(language, None) -# self.assertEqual(language.marked_for_deletion, True) -# -# -# class TestDeleteLanguageFailureCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# from lingvodoc.models import ( -# Base -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_delete_language(self): -# from lingvodoc.views import delete_language -# request = testing.DummyRequest() -# request.matchdict['client_id'] = 42 -# request.matchdict['object_id'] = 42 -# response = delete_language(request) -# self.assertEqual(response['status'], HTTPNotFound.code) -# -# -# class TestCreateLanguageSuccessCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# self.config.testing_securitypolicy(userid='1', -# permissive=True) -# import webtest -# from pyramid import paster -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# myapp = paster.get_app('testing.ini') -# self.app = webtest.TestApp(myapp) -# from lingvodoc.models import ( -# Base, -# User, -# Client, -# Passhash, -# Locale, -# UserEntitiesTranslationString, -# Language -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# with transaction.manager: -# ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") -# DBSession.add(ru_locale) -# en_locale = Locale(id=2, shortcut="en", intl_name="English") -# DBSession.add(en_locale) -# DBSession.flush() -# new_user = User(id=1, login='test', default_locale_id = 1) -# new_pass = Passhash(password='pass') -# DBSession.add(new_pass) -# new_user.password = new_pass -# DBSession.add(new_user) -# new_client = Client(id=1, user=new_user) -# DBSession.add(new_client) -# new_uets= UserEntitiesTranslationString(client_id = 1, object_id = 1, locale_id=2, -# translation_string = 'imastring') -# DBSession.add(new_uets) -# new_lang = Language(client_id=1, object_id=1, translation_string='testy') -# DBSession.add(new_lang) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_create_language(self): -# from lingvodoc.models import ( -# Language, -# UserEntitiesTranslationString -# ) -# response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) -# response = self.app.post_json('/language', params={'translation_string': 'imastring', -# 'translation': 'imatranslation'}) -# self.assertEqual(response.status_int , HTTPOk.code) -# -# language = DBSession.query(Language).filter_by(translation_string='imastring').first() -# self.assertNotEqual(language, None) -# self.assertEqual(language.object_id, 1) -# self.assertEqual(language.client_id, 2) -# -# uets = DBSession.query(UserEntitiesTranslationString).\ -# filter_by(translation_string='imastring', locale_id=2).first() -# self.assertNotEqual(uets, None) -# self.assertEqual(uets.translation, None) -# -# uets = DBSession.query(UserEntitiesTranslationString).\ -# filter_by(translation_string='imastring', locale_id=1).first() -# self.assertNotEqual(uets, None) -# self.assertEqual(uets.translation, 'imatranslation') -# -# def test_create_language_with_parent(self): -# from lingvodoc.models import ( -# Language, -# UserEntitiesTranslationString -# ) -# response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) -# response = self.app.post_json('/language', params={'translation_string': 'imastring2', -# 'translation': 'imatranslation2', -# 'parent_object_id': 1, 'parent_client_id': 1}) -# self.assertEqual(response.status_int , HTTPOk.code) -# -# language = DBSession.query(Language).filter_by(translation_string='imastring2').first() -# self.assertNotEqual(language, None) -# self.assertEqual(language.object_id, 1) -# self.assertEqual(language.client_id, 2) -# -# parent = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() -# self.assertNotEqual(parent, None) -# self.assertEqual(parent, language.parent) -# -# uets = DBSession.query(UserEntitiesTranslationString).\ -# filter_by(translation_string='imastring2', locale_id=1).first() -# self.assertNotEqual(uets, None) -# self.assertEqual(uets.translation, 'imatranslation2') -# -# -# class TestCreateLanguageFailureCondition(unittest.TestCase): -# -# def setUp(self): -# self.config = testing.setUp() -# self.config.testing_securitypolicy(userid='1', -# permissive=True) -# import webtest -# from pyramid import paster -# from sqlalchemy import create_engine -# engine = create_engine('sqlite://') -# myapp = paster.get_app('testing.ini') -# self.app = webtest.TestApp(myapp) -# from lingvodoc.models import ( -# Base -# ) -# DBSession.configure(bind=engine) -# Base.metadata.create_all(engine) -# -# def tearDown(self): -# DBSession.remove() -# testing.tearDown() -# -# def test_create_language(self): -# response = self.app.post_json('/language', -# params={'translation_string': 'imastring'}, status = HTTPBadRequest.code) -# self.assertEqual(response.status_int, HTTPBadRequest.code) -# -# +# +# NOTE +# +# See information on how tests are organized and how they should work in the tests' package __init__.py file +# (currently lingvodoc/tests/__init__.py). +# + + +import unittest +import transaction + +from pyramid import testing + +from lingvodoc.models import DBSession +from pyramid.httpexceptions import HTTPNotFound, HTTPOk, HTTPBadRequest, HTTPConflict, HTTPInternalServerError + +import pytest + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestViewLanguageSuccessCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + from lingvodoc.models import ( + Base, + Language, + UserEntitiesTranslationString, + Locale + ) + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") + DBSession.add(ru_locale) + DBSession.flush() + new_uets = UserEntitiesTranslationString(object_id = 1, client_id = 1, locale_id=1, + translation_string = 'test', translation = 'working') + DBSession.add(new_uets) + new_lang=Language(client_id=1, object_id=1, translation_string = 'test') + DBSession.add(new_lang) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_view_language(self): + from lingvodoc.views import view_language + request = testing.DummyRequest() + request.matchdict['client_id'] = 1 + request.matchdict['object_id'] = 1 + response = view_language(request) + self.assertEqual(response['status'], HTTPOk.code) + self.assertEqual(response['translation_string'], 'working') + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestViewLanguageFailureCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + from lingvodoc.models import ( + Base + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_view_language(self): + from lingvodoc.views import view_language + request = testing.DummyRequest() + request.matchdict['client_id'] = 42 + request.matchdict['object_id'] = 42 + response = view_language(request) + self.assertEqual(response['status'], HTTPNotFound.code) + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestEditLanguageSuccessCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + import webtest + from pyramid import paster + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + myapp = paster.get_app('testing.ini') + self.app = webtest.TestApp(myapp) + from lingvodoc.models import ( + Base, + Language, + Locale, + UserEntitiesTranslationString, + User, + Passhash, + Client + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") + DBSession.add(ru_locale) + en_locale = Locale(id=2, shortcut="en", intl_name="English") + DBSession.add(en_locale) + DBSession.flush() + new_user = User(id=1, login='test', default_locale_id = 1) + new_pass = Passhash(password='pass') + DBSession.add(new_pass) + new_user.password = new_pass + DBSession.add(new_user) + new_client = Client(id=1, user=new_user) + DBSession.add(new_client) + DBSession.flush() + new_uets = UserEntitiesTranslationString(object_id = 1, client_id = 1, locale_id=1, + translation_string = 'test', translation = 'not working') + DBSession.add(new_uets) + new_lang = Language(client_id=1, object_id=1, translation_string='test') + DBSession.add(new_lang) + new_lang = Language(client_id=1, object_id=2, translation_string='testy') + DBSession.add(new_lang) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_edit_language_name(self): + from lingvodoc.models import ( + Language, + UserEntitiesTranslationString + ) + response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) + response = self.app.put_json('/language/1/1', params={'translation_string': 'test', 'translation': 'working'}) + self.assertEqual(response.status_int, HTTPOk.code) + language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() + self.assertNotEqual(language, None) + uets = DBSession.query(UserEntitiesTranslationString).\ + filter_by(translation_string=language.translation_string, locale_id=1).first() + self.assertNotEqual(uets, None) + self.assertEqual(uets.translation, 'working') + + def test_edit_language_parent(self): + from lingvodoc.models import ( + Language + ) + response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) + response = self.app.put_json('/language/1/1', params={'parent_object_id': 2, 'parent_client_id': 1}) + self.assertEqual(response.status_int, HTTPOk.code) + language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() + self.assertNotEqual(language, None) + parent = DBSession.query(Language).filter_by(client_id=1, object_id=2).first() + self.assertNotEqual(parent, None) + self.assertEqual(language.parent, parent) + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestEditLanguageFailureCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + import webtest + from pyramid import paster + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + myapp = paster.get_app('testing.ini') + self.app = webtest.TestApp(myapp) + from lingvodoc.models import ( + Base, + Locale, + User, + Passhash, + Client + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") + DBSession.add(ru_locale) + en_locale = Locale(id=2, shortcut="en", intl_name="English") + DBSession.add(en_locale) + DBSession.flush() + new_user = User(id=1, login='test', default_locale_id = 1) + new_pass = Passhash(password='pass') + DBSession.add(new_pass) + new_user.password = new_pass + DBSession.add(new_user) + new_client = Client(id=1, user=new_user) + DBSession.add(new_client) + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_edit_language_without_login(self): + response = self.app.put_json('/language/42/42', + params={'translation_string': 'imastring', 'translation': 'imatranslation'}, + status = HTTPBadRequest.code) + self.assertEqual(response.status_int, HTTPBadRequest.code) + + def test_edit_language_with_login(self): + response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) + response = self.app.put_json('/language/42/42', + params={'translation_string': 'imastring', 'translation': 'imatranslation'}, + status = HTTPNotFound.code) + self.assertEqual(response.status_int, HTTPNotFound.code) + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestDeleteLanguageSuccessCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + from lingvodoc.models import ( + Base, + Language + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + new_lang = Language(client_id=1, object_id=1, translation_string='test') + DBSession.add(new_lang) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_delete_language(self): + from lingvodoc.views import delete_language + from lingvodoc.models import ( + Language + ) + request = testing.DummyRequest() + request.matchdict['client_id'] = 1 + request.matchdict['object_id'] = 1 + response = delete_language(request) + + self.assertEqual(response['status'], HTTPOk.code) + language = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() + self.assertNotEqual(language, None) + self.assertEqual(language.marked_for_deletion, True) + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestDeleteLanguageFailureCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + from lingvodoc.models import ( + Base + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_delete_language(self): + from lingvodoc.views import delete_language + request = testing.DummyRequest() + request.matchdict['client_id'] = 42 + request.matchdict['object_id'] = 42 + response = delete_language(request) + self.assertEqual(response['status'], HTTPNotFound.code) + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestCreateLanguageSuccessCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + self.config.testing_securitypolicy(userid='1', + permissive=True) + import webtest + from pyramid import paster + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + myapp = paster.get_app('testing.ini') + self.app = webtest.TestApp(myapp) + from lingvodoc.models import ( + Base, + User, + Client, + Passhash, + Locale, + UserEntitiesTranslationString, + Language + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + ru_locale = Locale(id=1, shortcut="ru", intl_name="Русский") + DBSession.add(ru_locale) + en_locale = Locale(id=2, shortcut="en", intl_name="English") + DBSession.add(en_locale) + DBSession.flush() + new_user = User(id=1, login='test', default_locale_id = 1) + new_pass = Passhash(password='pass') + DBSession.add(new_pass) + new_user.password = new_pass + DBSession.add(new_user) + new_client = Client(id=1, user=new_user) + DBSession.add(new_client) + new_uets= UserEntitiesTranslationString(client_id = 1, object_id = 1, locale_id=2, + translation_string = 'imastring') + DBSession.add(new_uets) + new_lang = Language(client_id=1, object_id=1, translation_string='testy') + DBSession.add(new_lang) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_create_language(self): + from lingvodoc.models import ( + Language, + UserEntitiesTranslationString + ) + response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) + response = self.app.post_json('/language', params={'translation_string': 'imastring', + 'translation': 'imatranslation'}) + self.assertEqual(response.status_int , HTTPOk.code) + + language = DBSession.query(Language).filter_by(translation_string='imastring').first() + self.assertNotEqual(language, None) + self.assertEqual(language.object_id, 1) + self.assertEqual(language.client_id, 2) + + uets = DBSession.query(UserEntitiesTranslationString).\ + filter_by(translation_string='imastring', locale_id=2).first() + self.assertNotEqual(uets, None) + self.assertEqual(uets.translation, None) + + uets = DBSession.query(UserEntitiesTranslationString).\ + filter_by(translation_string='imastring', locale_id=1).first() + self.assertNotEqual(uets, None) + self.assertEqual(uets.translation, 'imatranslation') + + def test_create_language_with_parent(self): + from lingvodoc.models import ( + Language, + UserEntitiesTranslationString + ) + response = self.app.post_json('/signin', params={'login': 'test', 'password': 'pass'}) + response = self.app.post_json('/language', params={'translation_string': 'imastring2', + 'translation': 'imatranslation2', + 'parent_object_id': 1, 'parent_client_id': 1}) + self.assertEqual(response.status_int , HTTPOk.code) + + language = DBSession.query(Language).filter_by(translation_string='imastring2').first() + self.assertNotEqual(language, None) + self.assertEqual(language.object_id, 1) + self.assertEqual(language.client_id, 2) + + parent = DBSession.query(Language).filter_by(client_id=1, object_id=1).first() + self.assertNotEqual(parent, None) + self.assertEqual(parent, language.parent) + + uets = DBSession.query(UserEntitiesTranslationString).\ + filter_by(translation_string='imastring2', locale_id=1).first() + self.assertNotEqual(uets, None) + self.assertEqual(uets.translation, 'imatranslation2') + + +@pytest.mark.skip(reason = 'Unconverted test from the previous version.') +class TestCreateLanguageFailureCondition(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + self.config.testing_securitypolicy(userid='1', + permissive=True) + import webtest + from pyramid import paster + from sqlalchemy import create_engine + engine = create_engine('sqlite://') + myapp = paster.get_app('testing.ini') + self.app = webtest.TestApp(myapp) + from lingvodoc.models import ( + Base + ) + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + + def tearDown(self): + DBSession.remove() + testing.tearDown() + + def test_create_language(self): + response = self.app.post_json('/language', + params={'translation_string': 'imastring'}, status = HTTPBadRequest.code) + self.assertEqual(response.status_int, HTTPBadRequest.code) + diff --git a/tox.ini b/tox.ini index cd3ff4011..14612be02 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,14 @@ -# content of: tox.ini , put in same dir as setup.py +# content of: tox.ini, put in same dir as setup.py + [tox] envlist = py34 + [testenv] changedir=tests commands = nosetests --nocapture {posargs} -deps = -r{toxinidir}/requirements.txt \ No newline at end of file +deps = -r{toxinidir}/requirements.txt + +[pytest] +addopts = --color=no +python_files = test*.py +testpaths = tests