Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added some JEST tests to cover skeleton basic features #4865

Merged
merged 13 commits into from
Sep 2, 2022
12 changes: 1 addition & 11 deletions cvat-core/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
// SPDX-License-Identifier: MIT

module.exports = {
env: {
'jest/globals': true,
},
ignorePatterns: [
'.eslintrc.js',
'webpack.config.js',
Expand All @@ -14,17 +11,10 @@ module.exports = {
'src/3rdparty/**',
'node_modules/**',
'dist/**',
'tests/**/*.js',
],
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
ignorePatterns: ['tests/**/*.js'],
plugins: ['jest'],
rules: {
'jest/no-disabled-tests': 'warn',
'jest/no-focused-tests': 'error',
'jest/no-identical-title': 'error',
'jest/prefer-to-have-length': 'warn',
}
};
99 changes: 99 additions & 0 deletions cvat-core/tests/api/annotations.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ describe('Feature: get annotations', () => {
expect(annotations).toHaveLength(1);
expect(annotations[0].shapeType).toBe('ellipse');
});

test('get skeletons with a filter', async () => {
const job = (await window.cvat.jobs.get({ jobID: 40 }))[0];
const annotations = await job.annotations.get(0, false, JSON.parse('[{"and":[{"==":[{"var":"shape"},"skeleton"]}]}]'));
expect(Array.isArray(annotations)).toBeTruthy();
expect(annotations).toHaveLength(2);
for (const object of annotations) {
expect(object.shapeType).toBe('skeleton');
expect(object.elements).toBeInstanceOf(Array);
const label = object.label;
let points = [];
object.elements.forEach((element, idx) => {
expect(element).toBeInstanceOf(cvat.classes.ObjectState);
expect(element.label.id).toBe(label.structure.sublabels[idx].id);
expect(element.shapeType).toBe('points');
points = [...points, ...element.points];
});
expect(points).toEqual(object.points);
}

expect(annotations[0].shapeType).toBe('skeleton');
})
});

describe('Feature: get interpolated annotations', () => {
Expand Down Expand Up @@ -351,6 +373,68 @@ describe('Feature: put annotations', () => {
zOrder: 0,
})).toThrow(window.cvat.exceptions.ArgumentError);
});

test('put a skeleton shape to a job', async() => {
const job = (await window.cvat.jobs.get({ jobID: 40 }))[0];
const label = job.labels[0];
await job.annotations.clear(true);
await job.annotations.clear();
klakhov marked this conversation as resolved.
Show resolved Hide resolved
const skeleton = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ShapeType.SKELETON,
points: [],
label,
elements: label.structure.sublabels.map((sublabel, idx) => ({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ShapeType.POINTS,
points: [idx * 10, idx * 10],
label: sublabel,
}))
});

await job.annotations.put([skeleton]);
const annotations = await job.annotations.get(0);
expect(annotations.length).toBe(1);
expect(annotations[0].objectType).toBe(window.cvat.enums.ObjectType.SHAPE);
expect(annotations[0].shapeType).toBe(window.cvat.enums.ShapeType.SKELETON);
for (const element of annotations[0].elements) {
expect(element.objectType).toBe(window.cvat.enums.ObjectType.SHAPE);
expect(element.shapeType).toBe(window.cvat.enums.ShapeType.POINTS);
}
});

test('put a skeleton track to a task', async() => {
const task = (await window.cvat.tasks.get({ id: 40 }))[0];
const label = task.labels[0];
await task.annotations.clear(true);
await task.annotations.clear();
klakhov marked this conversation as resolved.
Show resolved Hide resolved
const skeleton = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: window.cvat.enums.ShapeType.SKELETON,
points: [],
label,
elements: label.structure.sublabels.map((sublabel, idx) => ({
frame: 0,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: window.cvat.enums.ShapeType.POINTS,
points: [idx * 10, idx * 10],
label: sublabel,
}))
});

await task.annotations.put([skeleton]);
const annotations = await task.annotations.get(2);
expect(annotations.length).toBe(1);
expect(annotations[0].objectType).toBe(window.cvat.enums.ObjectType.TRACK);
expect(annotations[0].shapeType).toBe(window.cvat.enums.ShapeType.SKELETON);
for (const element of annotations[0].elements) {
expect(element.objectType).toBe(window.cvat.enums.ObjectType.TRACK);
expect(element.shapeType).toBe(window.cvat.enums.ShapeType.POINTS);
}
});
});

describe('Feature: check unsaved changes', () => {
Expand Down Expand Up @@ -772,6 +856,21 @@ describe('Feature: get statistics', () => {
expect(statistics).toBeInstanceOf(window.cvat.classes.Statistics);
expect(statistics.total.total).toBe(1012);
});

test('get statistics from a job with skeletons', async () => {
const job = (await window.cvat.jobs.get({ jobID: 40 }))[0];
await job.annotations.clear(true);
const statistics = await job.annotations.statistics();
expect(statistics).toBeInstanceOf(window.cvat.classes.Statistics);
expect(statistics.total.total).toBe(30);
const labelName = job.labels[0].name;
expect(statistics.label[labelName].skeleton.shape).toBe(1);
expect(statistics.label[labelName].skeleton.track).toBe(1);
expect(statistics.label[labelName].manually).toBe(2);
expect(statistics.label[labelName].interpolated).toBe(3);
expect(statistics.label[labelName].total).toBe(5);

});
});

describe('Feature: select object', () => {
Expand Down
37 changes: 37 additions & 0 deletions cvat-core/tests/api/object-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,40 @@ describe('Feature: delete object', () => {
expect(annotationsAfter).toHaveLength(length - 1);
});
});

describe('Feature: skeletons', () => {
test('lock, hide, occluded, outside for skeletons', async () => {
const job = (await window.cvat.jobs.get({ jobID: 40 }))[0];
let [skeleton] = await job.annotations.get(0, false, JSON.parse('[{"and":[{"==":[{"var":"shape"},"skeleton"]}]}]'));
expect(skeleton.shapeType).toBe('skeleton');
skeleton.lock = true;
skeleton.outside = true;
skeleton.occluded = true;
skeleton.hidden = true;
skeleton = await skeleton.save();
expect(skeleton.lock).toBe(true);
expect(skeleton.outside).toBe(true);
expect(skeleton.occluded).toBe(true);
expect(skeleton.hidden).toBe(true);
expect(skeleton.elements).toBeInstanceOf(Array);
expect(skeleton.elements.length).toBe(skeleton.label.structure.sublabels.length);
for (const element of skeleton.elements) {
expect(element.lock).toBe(true);
expect(element.outside).toBe(true);
expect(element.occluded).toBe(true);
expect(element.hidden).toBe(true);
}

skeleton.elements[0].lock = false;
skeleton.elements[0].outside = false;
skeleton.elements[0].occluded = false;
skeleton.elements[0].hidden = false;
skeleton.elements[0].save();

[skeleton] = await job.annotations.get(0, false, JSON.parse('[{"and":[{"==":[{"var":"shape"},"skeleton"]}]}]'));
expect(skeleton.lock).toBe(false);
expect(skeleton.outside).toBe(false);
expect(skeleton.occluded).toBe(false);
expect(skeleton.hidden).toBe(false);
});
});
80 changes: 78 additions & 2 deletions cvat-core/tests/api/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Feature: get a list of tasks', () => {
test('get all tasks', async () => {
const result = await window.cvat.tasks.get();
expect(Array.isArray(result)).toBeTruthy();
expect(result).toHaveLength(6);
expect(result).toHaveLength(7);
for (const el of result) {
expect(el).toBeInstanceOf(Task);
}
Expand All @@ -34,6 +34,33 @@ describe('Feature: get a list of tasks', () => {
expect(result[0].id).toBe(3);
});

test('get a task with skeletons by an id', async () => {
const result = await window.cvat.tasks.get({
id: 40,
});

expect(Array.isArray(result)).toBeTruthy();
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(Task);
expect(result[0].id).toBe(40);
expect(result[0].labels).toBeInstanceOf(Array);

for (const label of result[0].labels) {
expect(label).toBeInstanceOf(window.cvat.classes.Label);
if (label.type === 'skeleton') {
expect(label.hasParent).toBe(false);
expect(label.structure.sublabels).toBeInstanceOf(Array);
expect(typeof label.structure.svg).toBe('string');
expect(label.structure.svg.length).not.toBe(0);

for (const sublabel of label.structure.sublabels) {
expect(sublabel).toBeInstanceOf(window.cvat.classes.Label);
expect(sublabel.hasParent).toBe(true);
}
}
}
});

test('get a task by an unknown id', async () => {
const result = await window.cvat.tasks.get({
id: 50,
Expand Down Expand Up @@ -154,12 +181,61 @@ describe('Feature: save a task', () => {
project_id: 2,
bug_tracker: 'bug tracker value',
image_quality: 50,
z_order: true,
});

const result = await task.save();
expect(result.projectId).toBe(2);
});

test('create a new task with skeletons', async () => {
const svgSpec = `
<line x1="65.11705780029297" y1="18.267141342163086" x2="27.49163818359375" y2="39.504600524902344" stroke="black" data-type="edge" data-node-from="3" stroke-width="0.5" data-node-to="5"></line>
<line x1="21.806020736694336" y1="18.099916458129883" x2="65.11705780029297" y2="18.267141342163086" stroke="black" data-type="edge" data-node-from="1" stroke-width="0.5" data-node-to="3"></line>
<line x1="61.10367965698242" y1="40.00627136230469" x2="21.806020736694336" y2="18.099916458129883" stroke="black" data-type="edge" data-node-from="4" stroke-width="0.5" data-node-to="1"></line>
<line x1="44.38127136230469" y1="7.397575378417969" x2="61.10367965698242" y2="40.00627136230469" stroke="black" data-type="edge" data-node-from="2" stroke-width="0.5" data-node-to="4">
</line><line x1="27.49163818359375" y1="39.504600524902344" x2="44.38127136230469" y2="7.397575378417969" stroke="black" data-type="edge" data-node-from="5" stroke-width="0.5" data-node-to="2"></line>
<circle r="1.5" stroke="black" fill="#b3b3b3" cx="21.806020736694336" cy="18.099916458129883" stroke-width="0.1" data-type="element node" data-element-id="1" data-node-id="1" data-label-name="1"></circle>
<circle r="1.5" stroke="black" fill="#b3b3b3" cx="44.38127136230469" cy="7.397575378417969" stroke-width="0.1" data-type="element node" data-element-id="2" data-node-id="2" data-label-name="2"></circle>
<circle r="1.5" stroke="black" fill="#b3b3b3" cx="65.11705780029297" cy="18.267141342163086" stroke-width="0.1" data-type="element node" data-element-id="3" data-node-id="3" data-label-name="3"></circle>
<circle r="1.5" stroke="black" fill="#b3b3b3" cx="61.10367965698242" cy="40.00627136230469" stroke-width="0.1" data-type="element node" data-element-id="4" data-node-id="4" data-label-name="4"></circle>
<circle r="1.5" stroke="black" fill="#b3b3b3" cx="27.49163818359375" cy="39.504600524902344" stroke-width="0.1" data-type="element node" data-element-id="5" data-node-id="5" data-label-name="5"></circle>
`;
klakhov marked this conversation as resolved.
Show resolved Hide resolved

const task = new window.cvat.classes.Task({
name: 'task with skeletons',
labels: [{
name: 'star skeleton',
type: 'skeleton',
attributes: [],
svg: svgSpec,
sublabels: [{
name: '1',
type: 'points',
attributes: []
}, {
name: '2',
type: 'points',
attributes: []
}, {
name: '3',
type: 'points',
attributes: []
}, {
name: '4',
type: 'points',
attributes: []
}, {
name: '5',
type: 'points',
attributes: []
}]
}],
project_id: null,
});

const result = await task.save();
expect(typeof result.id).toBe('number');
});
});

describe('Feature: delete a task', () => {
Expand Down
Loading