Skip to content

Commit

Permalink
Merge pull request #12 from ch-sa/pytest
Browse files Browse the repository at this point in the history
Add integration tests
  • Loading branch information
ch-sa authored Jun 13, 2021
2 parents 399c99a + 6b2d8b1 commit 526a223
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 22 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Integration Tests
on: [push, pull_request]

jobs:

testing:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
python-version: [3.6, 3.7, 3.8]
env:
DISPLAY: ':99.0'

steps:
- name: Get repository
uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: setup ${{ matrix.os }}
run: |
sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX
- name: Install freeglut
run: |
sudo apt-get install freeglut3 freeglut3-dev
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install -r requirements.txt
- name: Test with pytest
run: |
python -m pytest tests/integration/
25 changes: 11 additions & 14 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -1,40 +1,37 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
name: Unit Tests
on: [push, pull_request]

jobs:
build:

testing:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v2
- name: Get repository
uses: actions/checkout@v2

- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install -r requirements.txt
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
python -m pytest tests/
python -m pytest tests/unit/
2 changes: 1 addition & 1 deletion labelCloud/control/bbox_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def update_all(self):
@has_active_bbox_decorator
def update_z_dial(self):
self.view.dial_zrotation.blockSignals(True) # To brake signal loop
self.view.dial_zrotation.setValue(self.get_active_bbox().get_z_rotation())
self.view.dial_zrotation.setValue(int(self.get_active_bbox().get_z_rotation()))
self.view.dial_zrotation.blockSignals(False)

def update_curr_class(self):
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ numpy~=1.19.4
PyQt5~=5.15.2
PyOpenGL~=3.1.5
open3d~=0.11.2
pytest~=6.2.2
pytest~=6.2.2
pytest-qt~=4.0.1
39 changes: 39 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os
import sys

import pytest


def pytest_configure(config):
os.chdir("../labelCloud")
print(f"Set working directory to {os.getcwd()}.")

sys.path.insert(0, "labelCloud")
print(f"Added labelCloud to Python path.")

import app # preventing circular import


@pytest.fixture
def startup_pyqt(qtbot, qapp):
from control.controller import Controller
from view.gui import GUI

# Setup Model-View-Control structure
control = Controller()
view = GUI(control)
qtbot.addWidget(view)
qtbot.addWidget(view.glWidget)

# Install event filter to catch user interventions
qapp.installEventFilter(view)

# Start GUI
view.show()
return view, control


@pytest.fixture
def bbox():
from model.bbox import BBox
return BBox(cx=0, cy=0, cz=0, length=3, width=2, height=1)
114 changes: 114 additions & 0 deletions tests/integration/test_gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os
from PyQt5 import QtCore
from PyQt5.QtWidgets import QAbstractSlider

from control.config_manager import config


def test_gui(qtbot, startup_pyqt):
view, controller = startup_pyqt

assert len(controller.pcd_manager.pcds) > 0
os.remove("labels/exemplary.json")
assert len(os.listdir("labels")) == 0
qtbot.mouseClick(view.button_next_pcd, QtCore.Qt.LeftButton, delay=0)
assert len(os.listdir("labels")) == 1

bbox = controller.bbox_controller.bboxes[0]
bbox.center = (0, 0, 0)
controller.bbox_controller.set_active_bbox(0)
qtbot.mouseClick(view.button_right, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_up, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_backward, QtCore.Qt.LeftButton, delay=0)
assert bbox.center == (0.03, 0.03, 0.03)

view.close()


def test_bbox_control_with_buttons(qtbot, startup_pyqt, bbox):
view, controller = startup_pyqt

# Prepare test bounding box
controller.bbox_controller.bboxes = [bbox]
old_length, old_width, old_height = bbox.get_dimensions()
controller.bbox_controller.set_active_bbox(0)

# Translation
translation_step = config.getfloat("LABEL", "std_translation")
qtbot.mouseClick(view.button_right, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_up, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_backward, QtCore.Qt.LeftButton, delay=0)
assert bbox.center == (translation_step, translation_step, translation_step)
qtbot.mouseClick(view.button_left, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_down, QtCore.Qt.LeftButton, delay=0)
qtbot.mouseClick(view.button_forward, QtCore.Qt.LeftButton)
print("BBOX: %s" % [str(c) for c in bbox.get_center()])
assert bbox.center == (0.00, 0.00, 0.00)

# Scaling
scaling_step = config.getfloat("LABEL", "std_scaling")
qtbot.mouseClick(view.button_incr_dim, QtCore.Qt.LeftButton)
assert bbox.length == old_length + scaling_step
assert bbox.width == old_width / old_length * bbox.length
assert bbox.height == old_height / old_length * bbox.length

# Rotation
# TODO: Make dial configureable?
view.dial_zrotation.triggerAction(QAbstractSlider.SliderSingleStepAdd)
assert bbox.z_rotation == 1
view.dial_zrotation.triggerAction(QAbstractSlider.SliderPageStepAdd)
assert bbox.z_rotation == 11

view.close()


def test_bbox_control_with_keyboard(qtbot, startup_pyqt, qapp, bbox):
view, controller = startup_pyqt

# Prepare test bounding box
controller.bbox_controller.bboxes = [bbox]
controller.bbox_controller.set_active_bbox(0)

# Translation
translation_step = config.getfloat("LABEL", "std_translation")
for letter in "dqw":
qtbot.keyClick(view, letter)
assert bbox.center == (translation_step, translation_step, translation_step)
translation_step = config.getfloat("LABEL", "std_translation")
for letter in "aes":
qtbot.keyClick(view, letter)
assert bbox.center == (0, 0, 0)

for key in [QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp]:
qtbot.keyClick(view, key)
assert bbox.center == (translation_step, translation_step, translation_step)
for key in [QtCore.Qt.Key_Left, QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown]:
qtbot.keyClick(view, key)
assert bbox.center == (0, 0, 0)

# Rotation
rotation_step = config.getfloat("LABEL", "std_rotation")
config.set("USER_INTERFACE", "z_rotation_only", "False")
qtbot.keyClick(view, "y")
assert bbox.z_rotation == rotation_step
qtbot.keyClick(view, "x")
assert bbox.z_rotation == 0
qtbot.keyClick(view, QtCore.Qt.Key_Comma)
assert bbox.z_rotation == rotation_step
qtbot.keyClick(view, QtCore.Qt.Key_Period)
assert bbox.z_rotation == 0
qtbot.keyClick(view, "c")
assert bbox.y_rotation == rotation_step
qtbot.keyClick(view, "v")
assert bbox.y_rotation == 0
qtbot.keyClick(view, "b")
assert bbox.x_rotation == rotation_step
qtbot.keyClick(view, "n")
assert bbox.x_rotation == 0

# Shortcuts
qtbot.keyClick(view, QtCore.Qt.Key_Delete)
assert len(controller.bbox_controller.bboxes) == 0
assert controller.bbox_controller.get_active_bbox() is None

view.close()
41 changes: 41 additions & 0 deletions tests/integration/test_labeling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pytest
from PyQt5 import QtCore
from PyQt5.QtCore import QPoint

from control.config_manager import config
from model.bbox import BBox


def test_picking_mode(qtbot, startup_pyqt):
view, control = startup_pyqt
control.bbox_controller.bboxes = []

qtbot.mouseClick(view.button_activate_picking, QtCore.Qt.LeftButton, delay=1000)
qtbot.mouseClick(view.glWidget, QtCore.Qt.LeftButton, pos=QPoint(500, 500), delay=1000)

assert len(control.bbox_controller.bboxes) == 1
new_bbox = control.bbox_controller.bboxes[0]
assert new_bbox.center == tuple(pytest.approx(x, 0.01) for x in [-0.2479, -0.2245, 0.0447])

assert new_bbox.length == config.getfloat("LABEL", "std_boundingbox_length")
assert new_bbox.width == config.getfloat("LABEL", "std_boundingbox_width")
assert new_bbox.height == config.getfloat("LABEL", "std_boundingbox_height")
assert new_bbox.z_rotation == new_bbox.y_rotation == new_bbox.x_rotation == 0


def test_spanning_mode(qtbot, startup_pyqt):
view, control = startup_pyqt
control.bbox_controller.bboxes = []
config.set("USER_INTERFACE", "z_rotation_only", "True")

qtbot.mouseClick(view.button_activate_spanning, QtCore.Qt.LeftButton, delay=10)
qtbot.mouseClick(view.glWidget, QtCore.Qt.LeftButton, pos=QPoint(431, 475), delay=20)
qtbot.mouseClick(view.glWidget, QtCore.Qt.LeftButton, pos=QPoint(506, 367), delay=20)
qtbot.mouseClick(view.glWidget, QtCore.Qt.LeftButton, pos=QPoint(572, 439), delay=20)
qtbot.mouseClick(view.glWidget, QtCore.Qt.LeftButton, pos=QPoint(607, 556), delay=20)

assert len(control.bbox_controller.bboxes) == 1
new_bbox: BBox = control.bbox_controller.bboxes[0]
assert new_bbox.center == tuple(pytest.approx(x, 0.01) for x in [-0.2100, -0.2348, 0.0568])
assert new_bbox.get_dimensions() == tuple(pytest.approx(x, 0.01) for x in [0.7344, 0.5305, 0.1212])
assert new_bbox.get_rotations() == tuple(pytest.approx(x % 360, 0.5) for x in [0, 0, 55.2205])
4 changes: 0 additions & 4 deletions tests/preparation.py

This file was deleted.

12 changes: 12 additions & 0 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import os
import sys


def pytest_configure(config):
os.chdir("../labelCloud")
print(f"Set working directory to {os.getcwd()}.")

sys.path.insert(0, "labelCloud")
print(f"Added labelCloud to Python path.")

import app # preventing circular import
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import json
import os
import pytest
import preparation

from model.bbox import BBox
from control.label_manager import LabelManager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os

import pytest
import preparation
from control.label_manager import LabelManager


Expand Down

0 comments on commit 526a223

Please sign in to comment.