Skip to content

Commit 2224180

Browse files
committed
CI: add evaluation unit tests
1 parent 7421d99 commit 2224180

File tree

7 files changed

+101426
-3067
lines changed

7 files changed

+101426
-3067
lines changed

.github/workflows/tests.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Run Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v3
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v3
20+
with:
21+
python-version: '3.8'
22+
23+
- name: Install uv
24+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
25+
26+
- name: Install dependencies
27+
run: |
28+
source $HOME/.cargo/env
29+
uv sync --group=dev
30+
31+
- name: Run tests
32+
run: |
33+
source $HOME/.cargo/env
34+
uv run pytest
35+

.gitlab-ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ variables:
66
stages:
77
- setup
88
- static-analysis
9+
- test
910
- doc
1011

1112
.default-before-script: &default-before-script
@@ -39,6 +40,18 @@ ruff-lint:
3940
tags:
4041
- docker
4142

43+
pytest:
44+
stage: test
45+
image: python:3.8-buster
46+
before_script:
47+
- *default-before-script
48+
- uv pip install -U pip wheel setuptools
49+
- uv sync --group=dev
50+
script:
51+
- uv run --no-sync pytest
52+
tags:
53+
- docker
54+
4255
ruff-format:
4356
stage: static-analysis
4457
image: python:3.8-buster

pyproject.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ dependencies = [
4747
test = [
4848
"pytest",
4949
"pytest-cov",
50+
"pytest-mock",
5051
]
5152
dev = [
5253
"black",
5354
"isort",
5455
"pytest",
5556
"pytest-cov",
57+
"pytest-mock",
5658
"ruff==0.8.6",
5759
]
5860
doc = [
@@ -104,12 +106,14 @@ models-segment_anything = [
104106
test = [
105107
"pytest",
106108
"pytest-cov",
109+
"pytest-mock",
107110
]
108111
dev = [
109112
"black",
110113
"isort",
111114
"pytest",
112115
"pytest-cov",
116+
"pytest-mock",
113117
"ruff==0.8.6",
114118
]
115119
doc = [
@@ -307,3 +311,8 @@ members = [
307311
[tool.setuptools.packages.find]
308312
where = ["."]
309313
include = ["compressai_vision", "compressai_vision.*"]
314+
315+
[tool.pytest.ini_options]
316+
testpaths = [
317+
"tests",
318+
]

tests/__init__.py

Whitespace-only changes.

tests/evaluators/__init__.py

Whitespace-only changes.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Copyright (c) 2022-2024, InterDigital Communications, Inc
2+
# All rights reserved.
3+
4+
# Redistribution and use in source and binary forms, with or without
5+
# modification, are permitted (subject to the limitations in the disclaimer
6+
# below) provided that the following conditions are met:
7+
8+
# * Redistributions of source code must retain the above copyright notice,
9+
# this list of conditions and the following disclaimer.
10+
# * Redistributions in binary form must reproduce the above copyright notice,
11+
# this list of conditions and the following disclaimer in the documentation
12+
# and/or other materials provided with the distribution.
13+
# * Neither the name of InterDigital Communications, Inc nor the names of its
14+
# contributors may be used to endorse or promote products derived from this
15+
# software without specific prior written permission.
16+
17+
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
18+
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19+
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20+
# NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25+
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27+
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
30+
import json
31+
import os
32+
import pytest
33+
import torch
34+
35+
from unittest.mock import MagicMock, patch
36+
37+
from compressai_vision.evaluators import COCOEVal
38+
39+
def mock_coco_api(annotation_file):
40+
# Create a mock COCO API object
41+
coco_api = MagicMock()
42+
coco_api.anns = {1: {'image_id': 1, 'category_id': 1, 'bbox': [10, 10, 50, 50]}}
43+
return coco_api
44+
45+
@pytest.fixture
46+
def mock_dataset():
47+
dataset = MagicMock()
48+
dataset.dataset_name = "mock_coco_dataset"
49+
dataset.annotation_path = "mock_annotations.json"
50+
with open(dataset.annotation_path, 'w') as f:
51+
json.dump({
52+
'images': [{'id': 1, 'width': 640, 'height': 480}],
53+
'annotations': [{'id': 1, 'image_id': 1, 'category_id': 1, 'bbox': [10, 10, 50, 50]}],
54+
'categories': [{'id': 1, 'name': 'person'}]
55+
}, f)
56+
yield dataset
57+
os.remove(dataset.annotation_path)
58+
59+
@patch('detectron2.evaluation.COCOEvaluator', autospec=True)
60+
@patch('compressai_vision.evaluators.evaluators.deccode_compressed_rle')
61+
def test_coco_eval(mock_deccode, mock_evaluator, mock_dataset):
62+
# Configure the mock to have the expected attributes
63+
mock_coco_api_obj = MagicMock()
64+
mock_coco_api_obj.anns = {}
65+
mock_evaluator_instance = mock_evaluator.return_value
66+
mock_evaluator_instance._coco_api = mock_coco_api_obj
67+
mock_evaluator_instance.evaluate.return_value = {"AP": 50.0}
68+
69+
evaluator = COCOEVal(
70+
datacatalog_name="MPEGOIV6",
71+
dataset_name="mock_coco_dataset",
72+
dataset=mock_dataset,
73+
output_dir="./test_output"
74+
)
75+
76+
gt = [{'image_id': 1, 'width': 640, 'height': 480, 'image': torch.zeros(3, 480, 640)}]
77+
pred = [{'instances': MagicMock()}]
78+
79+
evaluator.digest(gt, pred)
80+
mock_evaluator.return_value.process.assert_called_once_with(gt, pred)
81+
82+
evaluator.results()
83+
mock_evaluator.return_value.evaluate.assert_called_once()

0 commit comments

Comments
 (0)