simulator: test_qa: Add some basic docstring tests
This one picked up a lot of inconsistancy so the changes here are pretty big. Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
This commit is contained in:
parent
f7ef165433
commit
39d8783055
14 changed files with 126 additions and 74 deletions
|
@ -21,8 +21,7 @@ treated as examples they are described in detail as part of the
|
||||||
* :py:class:`.SoftwareApp`
|
* :py:class:`.SoftwareApp`
|
||||||
* :py:class:`.StepCounterApp`
|
* :py:class:`.StepCounterApp`
|
||||||
* :py:class:`.StopwatchApp`
|
* :py:class:`.StopwatchApp`
|
||||||
* :py:class:`.TestApp`
|
* :py:class:`.TemplateApp`
|
||||||
* :py:class:`.TemplateApp``
|
|
||||||
|
|
||||||
Watch faces
|
Watch faces
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Johannes Wache
|
# Copyright (C) 2020 Johannes Wache
|
||||||
"""Calculator application
|
"""Calculator
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
This is a simple calculator app that uses the build-in eval() function to
|
This is a simple calculator app that uses the build-in eval() function to
|
||||||
compute the solution.
|
compute the solution.
|
||||||
|
|
||||||
|
.. figure:: res/CalcApp.png
|
||||||
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp, fonts
|
import wasp, fonts
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Shows a time (as HH:MM) together with a battery meter and the date.
|
Shows a time (as HH:MM) together with a battery meter and the date.
|
||||||
|
|
||||||
|
.. figure:: res/ClockApp.png
|
||||||
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
@ -21,13 +24,7 @@ DIGITS = (
|
||||||
MONTH = 'JanFebMarAprMayJunJulAugSepOctNovDec'
|
MONTH = 'JanFebMarAprMayJunJulAugSepOctNovDec'
|
||||||
|
|
||||||
class ClockApp():
|
class ClockApp():
|
||||||
"""Simple digital clock application.
|
"""Simple digital clock application."""
|
||||||
|
|
||||||
.. figure:: res/ClockApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the clock application
|
|
||||||
"""
|
|
||||||
NAME = 'Clock'
|
NAME = 'Clock'
|
||||||
ICON = icons.clock
|
ICON = icons.clock
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
Shows a pure white screen with the backlight set to maximum.
|
Shows a pure white screen with the backlight set to maximum.
|
||||||
|
|
||||||
|
.. figure:: res/TorchApp.png
|
||||||
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
@ -12,13 +15,7 @@ import wasp
|
||||||
import icons
|
import icons
|
||||||
|
|
||||||
class TorchApp(object):
|
class TorchApp(object):
|
||||||
"""Trivial flashlight application.
|
"""Trivial flashlight application."""
|
||||||
|
|
||||||
.. figure:: res/TorchApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the flashlight application
|
|
||||||
"""
|
|
||||||
NAME = 'Torch'
|
NAME = 'Torch'
|
||||||
ICON = icons.torch
|
ICON = icons.torch
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
These three lines poems are fun to write and fit nicely on a tiny screen.
|
These three lines poems are fun to write and fit nicely on a tiny screen.
|
||||||
|
|
||||||
|
.. figure:: res/HaikuApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
If there is a file called haiku.txt in the flash filesystem then this app
|
If there is a file called haiku.txt in the flash filesystem then this app
|
||||||
allows it to be displayed three lines at a time using the pager.
|
allows it to be displayed three lines at a time using the pager.
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Daniel Thompson
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
|
|
||||||
|
"""Heart rate monitor
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A graphing heart rate monitor using a PPG sensor.
|
||||||
|
|
||||||
|
.. figure:: res/HeartApp.png
|
||||||
|
:width: 179
|
||||||
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import machine
|
import machine
|
||||||
import ppg
|
import ppg
|
||||||
|
|
||||||
class HeartApp():
|
class HeartApp():
|
||||||
"""Heart Rate Sensing application.
|
"""Heart rate monitor application."""
|
||||||
|
|
||||||
.. figure:: res/HeartApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the heart rate application
|
|
||||||
"""
|
|
||||||
NAME = 'Heart'
|
NAME = 'Heart'
|
||||||
|
|
||||||
def foreground(self):
|
def foreground(self):
|
||||||
|
|
|
@ -3,19 +3,16 @@
|
||||||
|
|
||||||
"""Application launcher
|
"""Application launcher
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. figure:: res/LauncherApp.png
|
||||||
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import icons
|
import icons
|
||||||
|
|
||||||
class LauncherApp():
|
class LauncherApp():
|
||||||
"""An application launcher application.
|
"""An application launcher application."""
|
||||||
|
|
||||||
.. figure:: res/LauncherApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the application launcher
|
|
||||||
"""
|
|
||||||
NAME = 'Launcher'
|
NAME = 'Launcher'
|
||||||
ICON = icons.app
|
ICON = icons.app
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020-21 Daniel Thompson
|
# Copyright (C) 2020-21 Daniel Thompson
|
||||||
|
|
||||||
|
"""Settings application
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Allows a very small set of user preferences (including the date and
|
||||||
|
time) to be set on the device itself.
|
||||||
|
|
||||||
|
.. figure:: res/SettingsApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The settings tool is not expected to comprehensively present every
|
||||||
|
user configurable preference. Some are better presented via a
|
||||||
|
companion app and some particular exotic ones are perhaps best
|
||||||
|
managed with a user-provided ``main.py``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import fonts
|
import fonts
|
||||||
import icons
|
import icons
|
||||||
|
|
||||||
class SettingsApp():
|
class SettingsApp():
|
||||||
"""Ultra-simple settings application.
|
"""Settings application."""
|
||||||
|
|
||||||
Currently the settings application contains only one setting: brightness
|
|
||||||
|
|
||||||
.. figure:: res/SettingsApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the settings application
|
|
||||||
"""
|
|
||||||
NAME = 'Settings'
|
NAME = 'Settings'
|
||||||
ICON = icons.settings
|
ICON = icons.settings
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Johannes Wache
|
# Copyright (C) 2020 Johannes Wache
|
||||||
|
|
||||||
"""
|
"""Snake Game
|
||||||
Snake Game
|
~~~~~~~~~~~~~
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
This is a classic arcade game called snake.
|
This is a classic arcade game called snake.
|
||||||
|
|
||||||
|
@ -174,4 +173,3 @@ class Snake():
|
||||||
draw = wasp.watch.drawable
|
draw = wasp.watch.drawable
|
||||||
draw.fill(x=self.oldtail[0],y=self.oldtail[1],w=15,h=15,bg=0x0000)
|
draw.fill(x=self.oldtail[0],y=self.oldtail[1],w=15,h=15,bg=0x0000)
|
||||||
draw.fill(x=self.body[-1][0]+1,y=self.body[-1][1]+1,w=13,h=13,bg=0xffff)
|
draw.fill(x=self.body[-1][0]+1,y=self.body[-1][1]+1,w=13,h=13,bg=0xffff)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Daniel Thompson
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
"""Wizard to generate main.py."""
|
"""Software
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
A tool to enable/disable applications.
|
||||||
|
|
||||||
|
.. figure:: res/SoftwareApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
Most applications are disabled by default at boot in order to conserve
|
||||||
|
RAM (which is in short supply and very useful to anyone wanting to
|
||||||
|
write an application). This tools allows us to boot and conserve RAM
|
||||||
|
whilst still allowing users to activate so many awesome applications!
|
||||||
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import icons
|
import icons
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Daniel Thompson
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
|
|
||||||
|
"""Step counter
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Provide a daily step count.
|
||||||
|
|
||||||
|
.. figure:: res/StepsApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
The step counts automatically reset at midnight.
|
||||||
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
|
||||||
import fonts
|
import fonts
|
||||||
|
@ -30,13 +41,7 @@ feet = (
|
||||||
)
|
)
|
||||||
|
|
||||||
class StepCounterApp():
|
class StepCounterApp():
|
||||||
"""Step counter application.
|
"""Step counter application."""
|
||||||
|
|
||||||
.. figure:: res/StepsApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the step counter application
|
|
||||||
"""
|
|
||||||
NAME = 'Steps'
|
NAME = 'Steps'
|
||||||
ICON = icons.app
|
ICON = icons.app
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Daniel Thompson
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
|
|
||||||
|
"""Stopwatch
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Simple stop/start watch with support for split times.
|
||||||
|
|
||||||
|
.. figure:: res/StopclockApp.png
|
||||||
|
:width: 179
|
||||||
|
"""
|
||||||
import wasp
|
import wasp
|
||||||
import icons
|
import icons
|
||||||
import fonts
|
import fonts
|
||||||
|
|
||||||
class StopwatchApp():
|
class StopwatchApp():
|
||||||
"""Stopwatch application.
|
"""Stopwatch application."""
|
||||||
|
|
||||||
.. figure:: res/StopclockApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the stopwatch application
|
|
||||||
"""
|
|
||||||
# Stopwatch requires too many pixels to fit into the launcher
|
# Stopwatch requires too many pixels to fit into the launcher
|
||||||
|
|
||||||
NAME = 'Stopclock'
|
NAME = 'Stopclock'
|
||||||
ICON = icons.app
|
ICON = icons.app
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
|
|
||||||
"""Self Tests
|
"""Self Tests
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A collection of tests used to develop features or provide useful metrics such
|
||||||
|
as performance indicators or memory usage.
|
||||||
|
|
||||||
|
.. figure:: res/SelfTestApp.png
|
||||||
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
@ -15,13 +21,7 @@ import machine
|
||||||
from apps.pager import PagerApp
|
from apps.pager import PagerApp
|
||||||
|
|
||||||
class TestApp():
|
class TestApp():
|
||||||
"""Simple test application.
|
"""Self test application."""
|
||||||
|
|
||||||
.. figure:: res/SelfTestApp.png
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
Screenshot of the self test application
|
|
||||||
"""
|
|
||||||
NAME = 'Self Test'
|
NAME = 'Self Test'
|
||||||
ICON = icons.app
|
ICON = icons.app
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import pytest
|
import pytest
|
||||||
import wasp
|
import wasp
|
||||||
|
import importlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
EXCLUDE = ('Notifications', 'Template', 'Demo')
|
EXCLUDE = ('Notifications', 'Template', 'Demo')
|
||||||
|
|
||||||
def test_screenshot(constructor):
|
|
||||||
if constructor.NAME in EXCLUDE:
|
|
||||||
return
|
|
||||||
fname = f'res/{constructor.NAME}App.png'.replace(' ', '')
|
|
||||||
assert os.path.exists(fname)
|
|
||||||
|
|
||||||
def test_screenshot_README(constructor):
|
def test_screenshot_README(constructor):
|
||||||
if constructor.NAME in EXCLUDE:
|
if constructor.NAME in EXCLUDE:
|
||||||
return
|
return
|
||||||
fname = f'res/{constructor.NAME}App.png'.replace(' ', '')
|
fname = f'res/{constructor.NAME}App.png'.replace(' ', '')
|
||||||
|
|
||||||
|
# A screenshot must exist for every application (press 's' in the
|
||||||
|
# simulator)
|
||||||
|
assert os.path.exists(fname)
|
||||||
|
|
||||||
|
# Every screenshot must be included in the README image gallery
|
||||||
with open('README.rst') as f:
|
with open('README.rst') as f:
|
||||||
readme = f.read()
|
readme = f.read()
|
||||||
assert fname in readme
|
assert fname in readme
|
||||||
|
|
||||||
def test_apps_documented(constructor):
|
def test_app_library(constructor):
|
||||||
if constructor.NAME in EXCLUDE:
|
if constructor.NAME in EXCLUDE:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -28,8 +28,32 @@ def test_apps_documented(constructor):
|
||||||
with open('docs/wasp.rst') as f:
|
with open('docs/wasp.rst') as f:
|
||||||
waspdoc = f.read()
|
waspdoc = f.read()
|
||||||
|
|
||||||
|
# Every application must be listed in either the
|
||||||
|
# Application Library or the Reference manual
|
||||||
needle = f'.. automodule:: {constructor.__module__}'
|
needle = f'.. automodule:: {constructor.__module__}'
|
||||||
assert needle in appdoc or needle in waspdoc
|
assert needle in appdoc or needle in waspdoc
|
||||||
|
|
||||||
|
# If an application is listed in the Reference manual
|
||||||
|
# then we need to make sure there is long to it from the
|
||||||
|
# Application Library
|
||||||
if needle in waspdoc:
|
if needle in waspdoc:
|
||||||
assert constructor.__name__ in appdoc
|
assert constructor.__name__ in appdoc
|
||||||
|
|
||||||
|
def test_docstrings(constructor):
|
||||||
|
if constructor.NAME in EXCLUDE:
|
||||||
|
return
|
||||||
|
fname = f'res/{constructor.NAME}App.png'.replace(' ', '')
|
||||||
|
|
||||||
|
class_doc = constructor.__doc__
|
||||||
|
module_doc = importlib.import_module(constructor.__module__).__doc__
|
||||||
|
|
||||||
|
# Screenshots should *not* appear in the constructor.
|
||||||
|
if constructor.__doc__:
|
||||||
|
assert fname not in constructor.__doc__
|
||||||
|
|
||||||
|
# Screenshots should appear in the full module documentation
|
||||||
|
assert f'.. figure:: {fname }' in module_doc
|
||||||
|
|
||||||
|
# The second line of the module documentation should be an
|
||||||
|
# underline (e.g. the first line must be a section header)
|
||||||
|
assert(module_doc.split('\n')[1].startswith('~~~~'))
|
||||||
|
|
Loading…
Reference in a new issue