提交 d85d7770 编写于 作者: B Boris Sekachev 提交者: Nikita Manovich

CVAT.js API Tests (#578)

* Added annotations dummy data

* Added test file

* Weak maps instead of regular dict

* Added 14 API tests

* Fixed put tests

* Some written tests and some additional checks

* Merge tests

* Split & group tests

* Clear annotations tests

* Statistics tests

* Added frames meta

* Selection tests & bug fixes

* Tests for frame

* ObjectState tests, many fixed bugs

* Object state tests

* Renamed method FrameData.frame() => FrameData.data()
上级 d939b9c3
......@@ -104,8 +104,12 @@
}
class Collection {
constructor(labels) {
this.labels = labels.reduce((labelAccumulator, label) => {
constructor(data) {
this.startFrame = data.startFrame;
this.stopFrame = data.stopFrame;
this.frameMeta = data.frameMeta;
this.labels = data.labels.reduce((labelAccumulator, label) => {
labelAccumulator[label.id] = label;
return labelAccumulator;
}, {});
......@@ -124,6 +128,7 @@
labels: this.labels,
collectionZ: this.collectionZ,
groups: this.groups,
frameMeta: this.frameMeta,
};
}
......@@ -208,7 +213,7 @@
const object = this.objects[state.clientID];
if (typeof (object) === 'undefined') {
throw new window.cvat.exceptions.ArgumentError(
'The object has not been saved yet. Call ObjectState.save() before you can merge it',
'The object has not been saved yet. Call ObjectState.put([state]) before you can merge it',
);
}
return object;
......@@ -216,6 +221,18 @@
const keyframes = {}; // frame: position
const { label, shapeType } = objectStates[0];
if (!(label.id in this.labels)) {
throw new window.cvat.exceptions.ArgumentError(
`Unknown label for the task: ${label.id}`,
);
}
if (!Object.values(window.cvat.enums.ObjectShape).includes(shapeType)) {
throw new window.cvat.exceptions.ArgumentError(
`Got unknown shapeType "${shapeType}"`,
);
}
const labelAttributes = label.attributes.reduce((accumulator, attribute) => {
accumulator[attribute.id] = attribute;
return accumulator;
......@@ -365,7 +382,9 @@
// Remove other shapes
for (const object of objectsForMerge) {
object.removed = true;
object.resetCache();
if (typeof (object.resetCache) === 'function') {
object.resetCache();
}
}
}
......@@ -376,7 +395,7 @@
const object = this.objects[objectState.clientID];
if (typeof (object) === 'undefined') {
throw new window.cvat.exceptions.ArgumentError(
'The object has not been saved yet. Call annotations.put(state) before',
'The object has not been saved yet. Call annotations.put([state]) before',
);
}
......@@ -385,7 +404,7 @@
}
const keyframes = Object.keys(object.shapes).sort((a, b) => +a - +b);
if (frame <= +keyframes[0]) {
if (frame <= +keyframes[0] || frame > keyframes[keyframes.length - 1]) {
return;
}
......@@ -463,7 +482,7 @@
const object = this.objects[state.clientID];
if (typeof (object) === 'undefined') {
throw new window.cvat.exceptions.ArgumentError(
'The object has not been saved yet. Call annotations.put(state) before',
'The object has not been saved yet. Call annotations.put([state]) before',
);
}
return object;
......@@ -472,8 +491,12 @@
const groupIdx = reset ? 0 : ++this.groups.max;
for (const object of objectsForGroup) {
object.group = groupIdx;
object.resetCache();
if (typeof (object.resetCache) === 'function') {
object.resetCache();
}
}
return groupIdx;
}
clear() {
......@@ -526,7 +549,7 @@
} else if (object instanceof Tag) {
objectType = 'tag';
} else {
throw window.cvat.exceptions.ScriptingError(
throw new window.cvat.exceptions.ScriptingError(
`Unexpected object type: "${objectType}"`,
);
}
......@@ -543,6 +566,7 @@
if (objectType === 'track') {
const keyframes = Object.keys(object.shapes)
.sort((a, b) => +a - +b).map(el => +el);
let prevKeyframe = keyframes[0];
let visible = false;
......@@ -560,6 +584,13 @@
labels[label].total++;
}
}
const lastKey = keyframes[keyframes.length - 1];
if (lastKey !== this.stopFrame && !object.shapes[lastKey].outside) {
const interpolated = this.stopFrame - lastKey;
labels[label].interpolated += interpolated;
labels[label].total += interpolated;
}
} else {
labels[label].manually++;
labels[label].total++;
......@@ -648,7 +679,7 @@
frame: state.frame,
group: 0,
label_id: state.label.id,
occluded: state.occluded,
occluded: state.occluded || false,
points: [...state.points],
type: state.shapeType,
z_order: 0,
......@@ -664,7 +695,7 @@
attributes: attributes
.filter(attr => labelAttributes[attr.spec_id].mutable),
frame: state.frame,
occluded: state.occluded,
occluded: state.occluded || false,
outside: false,
points: [...state.points],
type: state.shapeType,
......@@ -698,7 +729,7 @@
const object = this.objects[state.clientID];
if (typeof (object) === 'undefined') {
throw new window.cvat.exceptions.ArgumentError(
'The object has not been saved yet. Call annotations.put(state) before',
'The object has not been saved yet. Call annotations.put([state]) before',
);
}
......
......@@ -25,6 +25,94 @@
return objectState;
}
function checkNumberOfPoints(shapeType, points) {
if (shapeType === window.cvat.enums.ObjectShape.RECTANGLE) {
if (points.length / 2 !== 2) {
throw new window.cvat.exceptions.DataError(
`Rectangle must have 2 points, but got ${points.length / 2}`,
);
}
} else if (shapeType === window.cvat.enums.ObjectShape.POLYGON) {
if (points.length / 2 < 3) {
throw new window.cvat.exceptions.DataError(
`Polygon must have at least 3 points, but got ${points.length / 2}`,
);
}
} else if (shapeType === window.cvat.enums.ObjectShape.POLYLINE) {
if (points.length / 2 < 2) {
throw new window.cvat.exceptions.DataError(
`Polyline must have at least 2 points, but got ${points.length / 2}`,
);
}
} else if (shapeType === window.cvat.enums.ObjectShape.POINTS) {
if (points.length / 2 < 1) {
throw new window.cvat.exceptions.DataError(
`Points must have at least 1 points, but got ${points.length / 2}`,
);
}
} else {
throw new window.cvat.exceptions.ArgumentError(
`Unknown value of shapeType has been recieved ${shapeType}`,
);
}
}
function checkShapeArea(shapeType, points) {
const MIN_SHAPE_LENGTH = 3;
const MIN_SHAPE_AREA = 9;
if (shapeType === window.cvat.enums.ObjectShape.POINTS) {
return true;
}
let xmin = Number.MAX_SAFE_INTEGER;
let xmax = Number.MIN_SAFE_INTEGER;
let ymin = Number.MAX_SAFE_INTEGER;
let ymax = Number.MIN_SAFE_INTEGER;
for (let i = 0; i < points.length - 1; i += 2) {
xmin = Math.min(xmin, points[i]);
xmax = Math.max(xmax, points[i]);
ymin = Math.min(ymin, points[i + 1]);
ymax = Math.max(ymax, points[i + 1]);
}
if (shapeType === window.cvat.enums.ObjectShape.POLYLINE) {
const length = Math.max(
xmax - xmin,
ymax - ymin,
);
return length >= MIN_SHAPE_LENGTH;
}
const area = (xmax - xmin) * (ymax - ymin);
return area >= MIN_SHAPE_AREA;
}
function validateAttributeValue(value, attr) {
const { values } = attr;
const type = attr.inputType;
if (typeof (value) !== 'string') {
throw new window.cvat.exceptions.ArgumentError(
`Attribute value is expected to be string, but got ${typeof (value)}`,
);
}
if (type === window.cvat.enums.AttributeType.NUMBER) {
return +value >= +values[0]
&& +value <= +values[1]
&& !((+value - +values[0]) % +values[2]);
}
if (type === window.cvat.enums.AttributeType.CHECKBOX) {
return ['true', 'false'].includes(value.toLowerCase());
}
return values.includes(value);
}
class Annotation {
constructor(data, clientID, injection) {
this.taskLabels = injection.labels;
......@@ -66,10 +154,8 @@
constructor(data, clientID, color, injection) {
super(data, clientID, injection);
this.frameMeta = injection.frameMeta;
this.collectionZ = injection.collectionZ;
const z = this._getZ(this.frame);
z.max = Math.max(z.max, this.zOrder || 0);
z.min = Math.min(z.min, this.zOrder || 0);
this.color = color;
this.shapeType = null;
......@@ -85,19 +171,19 @@
}
save() {
throw window.cvat.exceptions.ScriptingError(
throw new window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}
get() {
throw window.cvat.exceptions.ScriptingError(
throw new window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}
toJSON() {
throw window.cvat.exceptions.ScriptingError(
throw new window.cvat.exceptions.ScriptingError(
'Is not implemented',
);
}
......@@ -123,6 +209,10 @@
this.points = data.points;
this.occluded = data.occluded;
this.zOrder = data.z_order;
const z = this._getZ(this.frame);
z.max = Math.max(z.max, this.zOrder || 0);
z.min = Math.min(z.min, this.zOrder || 0);
}
// Method is used to export data to the server
......@@ -195,22 +285,47 @@
}
if (updated.attributes) {
const labelAttributes = copy.label
.attributes.map(attr => `${attr.id}`);
const labelAttributes = copy.label.attributes
.reduce((accumulator, value) => {
accumulator[value.id] = value;
return accumulator;
}, {});
for (const attrID of Object.keys(data.attributes)) {
if (labelAttributes.includes(attrID)) {
copy.attributes[attrID] = data.attributes[attrID];
const value = data.attributes[attrID];
if (attrID in labelAttributes
&& validateAttributeValue(value, labelAttributes[attrID])) {
copy.attributes[attrID] = value;
} else {
throw new window.cvat.exceptions.ArgumentError(
`Trying to save unknown attribute with id ${attrID} and value ${value}`,
);
}
}
}
if (updated.points) {
checkObjectType('points', data.points, null, Array);
copy.points = [];
for (const coordinate of data.points) {
checkObjectType('coordinate', coordinate, 'number', null);
copy.points.push(coordinate);
checkNumberOfPoints(this.shapeType, data.points);
// cut points
const { width, height } = this.frameMeta[frame];
const cutPoints = [];
for (let i = 0; i < data.points.length - 1; i += 2) {
const x = data.points[i];
const y = data.points[i + 1];
checkObjectType('coordinate', x, 'number', null);
checkObjectType('coordinate', y, 'number', null);
cutPoints.push(
Math.clamp(x, 0, width),
Math.clamp(y, 0, height),
);
}
if (checkShapeArea(this.shapeType, cutPoints)) {
copy.points = cutPoints;
}
}
......@@ -340,7 +455,6 @@
{}, this.getPosition(frame),
{
attributes: this.getAttributes(frame),
label: this.label,
group: this.group,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: this.shapeType,
......@@ -354,7 +468,9 @@
this.cache[frame] = interpolation;
}
return JSON.parse(JSON.stringify(this.cache[frame]));
const result = JSON.parse(JSON.stringify(this.cache[frame]));
result.label = this.label;
return result;
}
neighborsFrames(targetFrame) {
......@@ -408,8 +524,7 @@
}
save(frame, data) {
if (this.lock || data.lock) {
this.lock = data.lock;
if (this.lock && data.lock) {
return objectStateFactory.call(this, frame, this.get(frame));
}
......@@ -430,34 +545,50 @@
this.appendDefaultAttributes.call(copy, copy.label);
}
if (updated.attributes) {
const labelAttributes = copy.label.attributes
.reduce((accumulator, value) => {
accumulator[value.id] = value;
return accumulator;
}, {});
const labelAttributes = copy.label.attributes
.reduce((accumulator, value) => {
accumulator[value.id] = value;
return accumulator;
}, {});
if (updated.attributes) {
for (const attrID of Object.keys(data.attributes)) {
if (attrID in labelAttributes) {
copy.attributes[attrID] = data.attributes[attrID];
if (!labelAttributes[attrID].mutable) {
this.attributes[attrID] = data.attributes[attrID];
} else {
// Mutable attributes will be updated later
positionUpdated = true;
}
const value = data.attributes[attrID];
if (attrID in labelAttributes
&& validateAttributeValue(value, labelAttributes[attrID])) {
copy.attributes[attrID] = value;
} else {
throw new window.cvat.exceptions.ArgumentError(
`Trying to save unknown attribute with id ${attrID} and value ${value}`,
);
}
}
}
if (updated.points) {
checkObjectType('points', data.points, null, Array);
copy.points = [];
for (const coordinate of data.points) {
checkObjectType('coordinate', coordinate, 'number', null);
copy.points.push(coordinate);
checkNumberOfPoints(this.shapeType, data.points);
// cut points
const { width, height } = this.frameMeta[frame];
const cutPoints = [];
for (let i = 0; i < data.points.length - 1; i += 2) {
const x = data.points[i];
const y = data.points[i + 1];
checkObjectType('coordinate', x, 'number', null);
checkObjectType('coordinate', y, 'number', null);
cutPoints.push(
Math.clamp(x, 0, width),
Math.clamp(y, 0, height),
);
}
if (checkShapeArea(this.shapeType, cutPoints)) {
copy.points = cutPoints;
positionUpdated = true;
}
positionUpdated = true;
}
if (updated.occluded) {
......@@ -499,6 +630,11 @@
copy.color = data.color;
}
if (updated.keyframe) {
// Just check here
checkObjectType('keyframe', data.keyframe, 'boolean', null);
}
// Commit all changes
for (const prop of Object.keys(copy)) {
if (prop in this) {
......@@ -508,8 +644,18 @@
this.cache[frame][prop] = copy[prop];
}
if (updated.attributes) {
// Mutable attributes will be updated below
for (const attrID of Object.keys(copy.attributes)) {
if (!labelAttributes[attrID].mutable) {
this.shapes[frame].attributes[attrID] = data.attributes[attrID];
this.shapes[frame].attributes[attrID] = data.attributes[attrID];
}
}
}
if (updated.label) {
for (const shape of this.shapes) {
for (const shape of Object.values(this.shapes)) {
shape.attributes = {};
}
}
......@@ -519,7 +665,7 @@
// Remove all cache after this keyframe because it have just become outdated
for (const cacheFrame in this.cache) {
if (+cacheFrame > frame) {
delete this.cache[frame];
delete this.cache[cacheFrame];
}
}
......@@ -535,7 +681,7 @@
// Remove all cache after this keyframe because it have just become outdated
for (const cacheFrame in this.cache) {
if (+cacheFrame > frame) {
delete this.cache[frame];
delete this.cache[cacheFrame];
}
}
......@@ -552,15 +698,9 @@
};
if (updated.attributes) {
const labelAttributes = this.label.attributes
.reduce((accumulator, value) => {
accumulator[value.id] = value;
return accumulator;
}, {});
// Unmutable attributes were updated above
for (const attrID of Object.keys(data.attributes)) {
if (attrID in labelAttributes && labelAttributes[attrID].mutable) {
for (const attrID of Object.keys(copy.attributes)) {
if (labelAttributes[attrID].mutable) {
this.shapes[frame].attributes[attrID] = data.attributes[attrID];
this.shapes[frame].attributes[attrID] = data.attributes[attrID];
}
......@@ -743,6 +883,7 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.RECTANGLE;
checkNumberOfPoints(this.shapeType, this.points);
}
static distance(points, x, y) {
......@@ -768,23 +909,25 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POLYGON;
checkNumberOfPoints(this.shapeType, this.points);
}
static distance(points, x, y) {
function position(x1, y1, x2, y2) {
return ((x1 - x) * (y2 - y) - (x2 - x) * (y1 - y));
return ((x2 - x1) * (y - y1) - (x - x1) * (y2 - y1));
}
let wn = 0;
const distances = [];
for (let i = 0; i < points.length; i += 2) {
for (let i = 0, j = points.length - 2; i < points.length - 1; j = i, i += 2) {
// Current point
const x1 = points[i];
const y1 = points[i + 1];
const x1 = points[j];
const y1 = points[j + 1];
// Next point
const x2 = i + 2 < points.length ? points[i + 2] : points[0];
const y2 = i + 3 < points.length ? points[i + 3] : points[1];
const x2 = points[i];
const y2 = points[i + 1];
// Check if a point is inside a polygon
// with a winding numbers algorithm
......@@ -795,25 +938,31 @@
wn++;
}
}
} else if (y2 < y) {
if (position(x1, y1, x2, y2) > 0) {
} else if (y2 <= y) {
if (position(x1, y1, x2, y2) < 0) {
wn--;
}
}
// Find the shortest distance from point to an edge
if (((x - x1) * (x2 - x)) >= 0 && ((y - y1) * (y2 - y)) >= 0) {
// Find the length of a perpendicular
// https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
distances.push(
Math.abs((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1) / Math
.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2)),
);
// Get an equation of a line in general
const aCoef = (y1 - y2);
const bCoef = (x2 - x1);
// Vector (aCoef, bCoef) is a perpendicular to line
// Now find the point where two lines
// (edge and its perpendicular through the point (x,y)) are cross
const xCross = x - aCoef;
const yCross = y - bCoef;
if (((xCross - x1) * (x2 - xCross)) >= 0
&& ((yCross - y1) * (y2 - yCross)) >= 0) {
// Cross point is on segment between p1(x1,y1) and p2(x2,y2)
distances.push(Math.sqrt(
Math.pow(x - xCross, 2)
+ Math.pow(y - yCross, 2),
));
} else {
// The link below works for lines (which have infinit length)
// There is a case when perpendicular doesn't cross the edge
// In this case we don't use the computed distance
// Instead we use just distance to the nearest point
distances.push(
Math.min(
Math.sqrt(Math.pow(x1 - x, 2) + Math.pow(y1 - y, 2)),
......@@ -835,6 +984,7 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POLYLINE;
checkNumberOfPoints(this.shapeType, this.points);
}
static distance(points, x, y) {
......@@ -878,6 +1028,7 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POINTS;
checkNumberOfPoints(this.shapeType, this.points);
}
static distance(points, x, y) {
......@@ -899,6 +1050,9 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.RECTANGLE;
for (const shape of Object.values(this.shapes)) {
checkNumberOfPoints(this.shapeType, shape.points);
}
}
interpolatePosition(leftPosition, rightPosition, targetFrame) {
......@@ -1220,7 +1374,7 @@
if (!targetMatched.length) {
// Prevent infinity loop
throw window.cvat.exceptions.ScriptingError('Interpolation mapping is empty');
throw new window.cvat.exceptions.ScriptingError('Interpolation mapping is empty');
}
while (!targetMatched.includes(prev)) {
......@@ -1310,6 +1464,9 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POLYGON;
for (const shape of Object.values(this.shapes)) {
checkNumberOfPoints(this.shapeType, shape.points);
}
}
}
......@@ -1317,6 +1474,9 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POLYLINE;
for (const shape of Object.values(this.shapes)) {
checkNumberOfPoints(this.shapeType, shape.points);
}
}
}
......@@ -1324,6 +1484,9 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = window.cvat.enums.ObjectShape.POINTS;
for (const shape of Object.values(this.shapes)) {
checkNumberOfPoints(this.shapeType, shape.points);
}
}
}
......
......@@ -102,7 +102,7 @@
} else if (typeof (object.id) === 'undefined') {
splitted.created[type].push(object);
} else {
throw window.cvat.exceptions.ScriptingError(
throw new window.cvat.exceptions.ScriptingError(
`Id of object is defined "${object.id}"`
+ 'but it absents in initial state',
);
......@@ -140,7 +140,7 @@
+ indexes.shapes.length + indexes.tags.length;
if (indexesLength !== savedLength) {
throw window.cvat.exception.ScriptingError(
throw new window.cvat.exception.ScriptingError(
'Number of indexes is differed by number of saved objects'
+ `${indexesLength} vs ${savedLength}`,
);
......
......@@ -11,9 +11,10 @@
const serverProxy = require('./server-proxy');
const Collection = require('./annotations-collection');
const AnnotationsSaver = require('./annotations-saver');
const { checkObjectType } = require('./common');
const jobCache = {};
const taskCache = {};
const jobCache = new WeakMap();
const taskCache = new WeakMap();
function getCache(sessionType) {
if (sessionType === 'task') {
......@@ -33,17 +34,32 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (!(session.id in cache)) {
if (!cache.has(session)) {
const rawAnnotations = await serverProxy.annotations
.getAnnotations(sessionType, session.id);
const collection = new Collection(session.labels || session.task.labels)
.import(rawAnnotations);
// Get meta information about frames
const startFrame = sessionType === 'job' ? session.startFrame : 0;
const stopFrame = sessionType === 'job' ? session.stopFrame : session.size - 1;
const frameMeta = {};
for (let i = startFrame; i <= stopFrame; i++) {
frameMeta[i] = await session.frames.get(i);
}
const collection = new Collection({
labels: session.labels || session.task.labels,
startFrame,
stopFrame,
frameMeta,
}).import(rawAnnotations);
const saver = new AnnotationsSaver(rawAnnotations.version, collection, session);
cache[session.id] = {
cache.set(session, {
collection,
saver,
};
});
}
}
......@@ -51,15 +67,15 @@
await getAnnotationsFromServer(session);
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
return cache[session.id].collection.get(frame, filter);
return cache.get(session).collection.get(frame, filter);
}
async function saveAnnotations(session, onUpdate) {
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
await cache[session.id].saver.save(onUpdate);
if (cache.has(session)) {
await cache.get(session).saver.save(onUpdate);
}
// If a collection wasn't uploaded, than it wasn't changed, finally we shouldn't save it
......@@ -69,11 +85,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.merge(objectStates);
if (cache.has(session)) {
return cache.get(session).collection.merge(objectStates);
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......@@ -82,11 +98,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.split(objectState, frame);
if (cache.has(session)) {
return cache.get(session).collection.split(objectState, frame);
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......@@ -95,11 +111,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.group(objectStates, reset);
if (cache.has(session)) {
return cache.get(session).collection.group(objectStates, reset);
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......@@ -108,23 +124,24 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].saver.hasUnsavedChanges();
if (cache.has(session)) {
return cache.get(session).saver.hasUnsavedChanges();
}
return false;
}
async function clearAnnotations(session, reload) {
checkObjectType('reload', reload, 'boolean', null);
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
cache[session.id].collection.clear();
if (cache.has(session)) {
cache.get(session).collection.clear();
}
if (reload) {
delete cache[session.id];
cache.delete(session);
await getAnnotationsFromServer(session);
}
}
......@@ -133,11 +150,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.statistics();
if (cache.has(session)) {
return cache.get(session).collection.statistics();
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......@@ -146,11 +163,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.put(objectStates);
if (cache.has(session)) {
return cache.get(session).collection.put(objectStates);
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......@@ -159,11 +176,11 @@
const sessionType = session instanceof window.cvat.classes.Task ? 'task' : 'job';
const cache = getCache(sessionType);
if (session.id in cache) {
return cache[session.id].collection.select(objectStates, x, y);
if (cache.has(session)) {
return cache.get(session).collection.select(objectStates, x, y);
}
throw window.cvat.exceptions.DataError(
throw new window.cvat.exceptions.DataError(
'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before',
);
}
......
......@@ -348,14 +348,12 @@
*/
config: {
/**
* @memberof module:API.cvat.config
* @property {string} backendAPI host with a backend api
* @memberof module:API.cvat.config
* @property {string} proxy Axios proxy settings.
* For more details please read <a href="https://github.com/axios/axios"> here </a>
* @memberof module:API.cvat.config
* @property {integer} preloadFrames the number of subsequent frames which are
* loaded in background
* @memberof module:API.cvat.config
* @property {integer} taskID this value is displayed in a logs if available
* @memberof module:API.cvat.config
* @property {integer} jobID this value is displayed in a logs if available
......@@ -364,7 +362,6 @@
* value which is displayed in a logs
* @memberof module:API.cvat.config
*/
preloadFrames: 300,
backendAPI: 'http://localhost:7000/api/v1',
proxy: false,
taskID: undefined,
......@@ -451,5 +448,9 @@
require('browser-env')();
}
Math.clamp = function (value, min, max) {
return Math.min(Math.max(value, min), max);
};
window.cvat = Object.freeze(implementAPI(cvat));
})();
......@@ -38,7 +38,7 @@
);
} else if (!fields[prop](filter[prop])) {
throw new window.cvat.exceptions.ArgumentError(
`Received filter property ${prop} is not satisfied for checker`,
`Received filter property "${prop}" is not satisfied for checker`,
);
}
}
......@@ -61,7 +61,7 @@
if (!(value instanceof instance)) {
if (value !== undefined) {
throw new window.cvat.exceptions.ArgumentError(
`${name} is expected to be ${instance.name}, but `
`"${name}" is expected to be ${instance.name}, but `
+ `"${value.constructor.name}" has been got`,
);
}
......
......@@ -59,7 +59,7 @@
/**
* Method returns URL encoded image which can be placed in the img tag
* @method frame
* @method data
* @returns {string}
* @memberof module:API.cvat.classes.FrameData
* @instance
......@@ -67,16 +67,16 @@
* @throws {module:API.cvat.exception.ServerError}
* @throws {module:API.cvat.exception.PluginError}
*/
async frame() {
async data() {
const result = await PluginRegistry
.apiWrapper.call(this, FrameData.prototype.frame);
.apiWrapper.call(this, FrameData.prototype.data);
return result;
}
}
FrameData.prototype.frame.implementation = async function () {
FrameData.prototype.data.implementation = async function () {
if (!(this.number in frameCache[this.tid])) {
const frame = await serverProxy.frames.getFrame(this.tid, this.number);
const frame = await serverProxy.frames.getData(this.tid, this.number);
if (window.URL.createObjectURL) { // browser env
const url = window.URL.createObjectURL(new Blob([frame]));
......
......@@ -153,12 +153,21 @@
* @name points
* @type {number[]}
* @memberof module:API.cvat.classes.ObjectState
* @throws {module:API.cvat.exceptions.ArgumentError}
* @instance
*/
get: () => data.points,
set: (points) => {
data.updateFlags.points = true;
data.points = [...points];
if (Array.isArray(points)) {
data.updateFlags.points = true;
data.points = [...points];
} else {
throw new window.cvat.exceptions.ArgumentError(
'Points are expected to be an array '
+ `but got ${typeof (points) === 'object'
? points.constructor.name : typeof (points)}`,
);
}
},
},
group: {
......@@ -252,14 +261,10 @@
get: () => data.attributes,
set: (attributes) => {
if (typeof (attributes) !== 'object') {
if (typeof (attributes) === 'undefined') {
throw new window.cvat.exceptions.ArgumentError(
'Expected attributes are object, but got undefined',
);
}
throw new window.cvat.exceptions.ArgumentError(
`Expected attributes are object, but got ${attributes.constructor.name}`,
'Attributes are expected to be an object '
+ `but got ${typeof (attributes) === 'object'
? attributes.constructor.name : typeof (attributes)}`,
);
}
......@@ -277,11 +282,17 @@
this.outside = serialized.outside;
this.keyframe = serialized.keyframe;
this.occluded = serialized.occluded;
this.attributes = serialized.attributes;
this.points = serialized.points;
this.color = serialized.color;
this.lock = serialized.lock;
// It can be undefined in a constructor and it can be defined later
if (typeof (serialized.points) !== 'undefined') {
this.points = serialized.points;
}
if (typeof (serialized.attributes) !== 'undefined') {
this.attributes = serialized.attributes;
}
data.updateFlags.reset();
}
......
......@@ -421,7 +421,7 @@
return response.data;
}
async function getFrame(tid, frame) {
async function getData(tid, frame) {
const { backendAPI } = window.cvat.config;
let response = null;
......@@ -629,7 +629,7 @@
frames: {
value: Object.freeze({
getFrame,
getData,
getMeta,
}),
writable: false,
......
......@@ -259,6 +259,7 @@
* @param {module:API.cvat.classes.ObjectState[]} data
* array of objects on the specific frame
* @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.DataError}
* @throws {module:API.cvat.exceptions.ArgumentError}
* @instance
* @async
......@@ -302,11 +303,13 @@
* @async
*/
/**
* Select shape under a cursor using math alghorithms
* Select shape under a cursor by using minimal distance
* between a cursor and a shape edge or a shape point
* For closed shapes a cursor is placed inside a shape
* @method select
* @memberof Session.annotations
* @param {module:API.cvat.classes.ObjectState[]} objectStates
* object which can be selected
* objects which can be selected
* @param {float} x horizontal coordinate
* @param {float} y vertical coordinate
* @returns {Object}
......@@ -659,7 +662,7 @@
return this;
}
throw window.cvat.exceptions.ArgumentError(
throw new window.cvat.exceptions.ArgumentError(
'Can not save job without and id',
);
};
......@@ -673,7 +676,7 @@
if (frame < this.startFrame || frame > this.stopFrame) {
throw new window.cvat.exceptions.ArgumentError(
`Frame ${frame} does not exist in the job`,
`The frame with number ${frame} is out of the job`,
);
}
......@@ -1262,9 +1265,15 @@
};
Task.prototype.frames.get.implementation = async function (frame) {
if (!Number.isInteger(frame) || frame < 0) {
throw new window.cvat.exceptions.ArgumentError(
`Frame must be a positive integer. Got: "${frame}"`,
);
}
if (frame >= this.size) {
throw new window.cvat.exceptions.ArgumentError(
`Frame ${frame} does not exist in the task`,
`The frame with number ${frame} is out of the task`,
);
}
......
/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
/* global
require:false
jest:false
describe:false
*/
// Setup mock for a server
jest.mock('../../src/server-proxy', () => {
const mock = require('../mocks/server-proxy.mock');
return mock;
});
// Initialize api
require('../../src/api');
// Test cases
describe('Feature: get annotations', () => {
test('get annotations from a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
expect(Array.isArray(annotations)).toBeTruthy();
expect(annotations).toHaveLength(11);
for (const state of annotations) {
expect(state).toBeInstanceOf(window.cvat.classes.ObjectState);
}
});
test('get annotations from a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 101 }))[0];
const annotations0 = await job.annotations.get(0);
const annotations10 = await job.annotations.get(10);
expect(Array.isArray(annotations0)).toBeTruthy();
expect(Array.isArray(annotations10)).toBeTruthy();
expect(annotations0).toHaveLength(1);
expect(annotations10).toHaveLength(2);
for (const state of annotations0.concat(annotations10)) {
expect(state).toBeInstanceOf(window.cvat.classes.ObjectState);
}
});
test('get annotations for frame out of task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
// Out of task
expect(task.annotations.get(500))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
// Out of task
expect(task.annotations.get(-1))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('get annotations for frame out of job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 101 }))[0];
// Out of segment
expect(job.annotations.get(500))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
// Out of segment
expect(job.annotations.get(-1))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
// TODO: Test filter (hasn't been implemented yet)
});
describe('Feature: put annotations', () => {
test('put a shape to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
let annotations = await task.annotations.get(1);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
await task.annotations.put([state]);
annotations = await task.annotations.get(1);
expect(annotations).toHaveLength(length + 1);
});
test('put a shape to a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(5);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 5,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
points: [0, 0, 100, 100],
occluded: false,
label: job.task.labels[0],
});
await job.annotations.put([state]);
annotations = await job.annotations.get(5);
expect(annotations).toHaveLength(length + 1);
});
test('put a track to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
let annotations = await task.annotations.get(1);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
await task.annotations.put([state]);
annotations = await task.annotations.get(1);
expect(annotations).toHaveLength(length + 1);
});
test('put a track to a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(5);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 5,
objectType: window.cvat.enums.ObjectType.TRACK,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
points: [0, 0, 100, 100],
occluded: false,
label: job.task.labels[0],
});
await job.annotations.put([state]);
annotations = await job.annotations.get(5);
expect(annotations).toHaveLength(length + 1);
});
test('put object without objectType to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 1,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('put shape with bad attributes to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
attributes: { 'bad key': 55 },
occluded: true,
label: task.labels[0],
});
expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('put shape without points and with invalud points to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
occluded: true,
points: [],
label: task.labels[0],
});
await expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.DataError);
delete state.points;
await expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.DataError);
state.points = ['150,50 250,30'];
expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('put shape without type to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.SHAPE,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('put shape without label and with bad label to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 1,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
});
await expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.label = 'bad label';
await expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.label = {};
await expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('put shape with bad frame to a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: '5',
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
expect(task.annotations.put([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: check unsaved changes', () => {
test('check unsaved changes in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
const annotations = await task.annotations.get(0);
annotations[0].keyframe = true;
await annotations[0].save();
expect(await task.annotations.hasUnsavedChanges()).toBe(true);
});
test('check unsaved changes in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
const annotations = await job.annotations.get(0);
annotations[0].occluded = true;
await annotations[0].save();
expect(await job.annotations.hasUnsavedChanges()).toBe(true);
});
});
describe('Feature: save annotations', () => {
test('create & save annotations for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
let annotations = await task.annotations.get(0);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
await task.annotations.put([state]);
expect(await task.annotations.hasUnsavedChanges()).toBe(true);
await task.annotations.save();
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
annotations = await task.annotations.get(0);
expect(annotations).toHaveLength(length + 1);
});
test('update & save annotations for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
annotations[0].occluded = true;
await annotations[0].save();
expect(await task.annotations.hasUnsavedChanges()).toBe(true);
await task.annotations.save();
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
});
test('delete & save annotations for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
await annotations[0].delete();
expect(await task.annotations.hasUnsavedChanges()).toBe(true);
await task.annotations.save();
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
});
test('create & save annotations for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(0);
const { length } = annotations;
const state = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: job.task.labels[0],
});
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
await job.annotations.put([state]);
expect(await job.annotations.hasUnsavedChanges()).toBe(true);
await job.annotations.save();
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
annotations = await job.annotations.get(0);
expect(annotations).toHaveLength(length + 1);
});
test('update & save annotations for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const annotations = await job.annotations.get(0);
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
annotations[0].points = [0, 100, 200, 300];
await annotations[0].save();
expect(await job.annotations.hasUnsavedChanges()).toBe(true);
await job.annotations.save();
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
});
test('delete & save annotations for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const annotations = await job.annotations.get(0);
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
await annotations[0].delete();
expect(await job.annotations.hasUnsavedChanges()).toBe(true);
await job.annotations.save();
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
});
});
describe('Feature: merge annotations', () => {
test('merge annotations in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const annotations1 = await task.annotations.get(1);
const states = [annotations0[0], annotations1[0]];
await task.annotations.merge(states);
const merged0 = (await task.annotations.get(0))
.filter(state => state.objectType === window.cvat.enums.ObjectType.TRACK);
const merged1 = (await task.annotations.get(1))
.filter(state => state.objectType === window.cvat.enums.ObjectType.TRACK);
expect(merged0).toHaveLength(1);
expect(merged1).toHaveLength(1);
expect(merged0[0].points).toEqual(states[0].points);
expect(merged1[0].points).toEqual(states[1].points);
});
test('merge annotations in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const annotations0 = await job.annotations.get(0);
const annotations1 = await job.annotations.get(1);
const states = [annotations0[0], annotations1[0]];
await job.annotations.merge(states);
const merged0 = (await job.annotations.get(0))
.filter(state => state.objectType === window.cvat.enums.ObjectType.TRACK);
const merged1 = (await job.annotations.get(1))
.filter(state => state.objectType === window.cvat.enums.ObjectType.TRACK);
expect(merged0).toHaveLength(1);
expect(merged1).toHaveLength(1);
expect(merged0[0].points).toEqual(states[0].points);
expect(merged1[0].points).toEqual(states[1].points);
});
test('trying to merge not object state', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const states = [annotations0[0], {}];
expect(task.annotations.merge(states))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to merge object state which is not saved in a collection', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const state = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
const states = [annotations0[0], state];
expect(task.annotations.merge(states))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to merge with bad label', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const annotations1 = await task.annotations.get(1);
const states = [annotations0[0], annotations1[0]];
states[0].label = new window.cvat.classes.Label({
id: 500,
name: 'new_label',
attributes: [],
});
expect(task.annotations.merge(states))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to merge with different shape types', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const annotations1 = (await task.annotations.get(1))
.filter(state => state.shapeType === window.cvat.enums.ObjectShape.POLYGON);
const states = [annotations0[0], annotations1[0]];
expect(task.annotations.merge(states))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to merge with different labels', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations0 = await task.annotations.get(0);
const annotations1 = await task.annotations.get(1);
const states = [annotations0[0], annotations1[0]];
states[1].label = new window.cvat.classes.Label({
id: 500,
name: 'new_label',
attributes: [],
});
expect(task.annotations.merge(states))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: split annotations', () => {
test('split annotations in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations4 = await task.annotations.get(4);
const annotations5 = await task.annotations.get(5);
expect(annotations4[0].clientID).toBe(annotations5[0].clientID);
await task.annotations.split(annotations5[0], 5);
const splitted4 = await task.annotations.get(4);
const splitted5 = (await task.annotations.get(5)).filter(state => !state.outside);
expect(splitted4[0].clientID).not.toBe(splitted5[0].clientID);
});
test('split annotations in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 101 }))[0];
const annotations4 = await job.annotations.get(4);
const annotations5 = await job.annotations.get(5);
expect(annotations4[0].clientID).toBe(annotations5[0].clientID);
await job.annotations.split(annotations5[0], 5);
const splitted4 = await job.annotations.get(4);
const splitted5 = (await job.annotations.get(5)).filter(state => !state.outside);
expect(splitted4[0].clientID).not.toBe(splitted5[0].clientID);
});
test('split on a bad frame', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations4 = await task.annotations.get(4);
const annotations5 = await task.annotations.get(5);
expect(annotations4[0].clientID).toBe(annotations5[0].clientID);
expect(task.annotations.split(annotations5[0], 'bad frame'))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: group annotations', () => {
test('group annotations in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
let annotations = await task.annotations.get(0);
const groupID = await task.annotations.group(annotations);
expect(typeof (groupID)).toBe('number');
annotations = await task.annotations.get(0);
for (const state of annotations) {
expect(state.group).toBe(groupID);
}
});
test('group annotations in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(0);
const groupID = await job.annotations.group(annotations);
expect(typeof (groupID)).toBe('number');
annotations = await job.annotations.get(0);
for (const state of annotations) {
expect(state.group).toBe(groupID);
}
});
test('trying to group object state which has not been saved in a collection', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
await task.annotations.clear(true);
const state = new window.cvat.classes.ObjectState({
frame: 0,
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.POLYGON,
points: [0, 0, 100, 0, 100, 50],
occluded: true,
label: task.labels[0],
});
expect(task.annotations.group([state]))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to group not object state', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
expect(task.annotations.group(annotations.concat({})))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: clear annotations', () => {
test('clear annotations in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
let annotations = await task.annotations.get(0);
expect(annotations.length).not.toBe(0);
await task.annotations.clear();
annotations = await task.annotations.get(0);
expect(annotations.length).toBe(0);
});
test('clear annotations in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(0);
expect(annotations.length).not.toBe(0);
await job.annotations.clear();
annotations = await job.annotations.get(0);
expect(annotations.length).toBe(0);
});
test('clear annotations with reload in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
let annotations = await task.annotations.get(0);
expect(annotations.length).not.toBe(0);
annotations[0].occluded = true;
await annotations[0].save();
expect(await task.annotations.hasUnsavedChanges()).toBe(true);
await task.annotations.clear(true);
annotations = await task.annotations.get(0);
expect(annotations.length).not.toBe(0);
expect(await task.annotations.hasUnsavedChanges()).toBe(false);
});
test('clear annotations with reload in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
let annotations = await job.annotations.get(0);
expect(annotations.length).not.toBe(0);
annotations[0].occluded = true;
await annotations[0].save();
expect(await job.annotations.hasUnsavedChanges()).toBe(true);
await job.annotations.clear(true);
annotations = await job.annotations.get(0);
expect(annotations.length).not.toBe(0);
expect(await job.annotations.hasUnsavedChanges()).toBe(false);
});
test('clear annotations with bad reload parameter', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
await task.annotations.clear(true);
expect(task.annotations.clear('reload'))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: get statistics', () => {
test('get statistics from a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
await task.annotations.clear(true);
const statistics = await task.annotations.statistics();
expect(statistics).toBeInstanceOf(window.cvat.classes.Statistics);
expect(statistics.total.total).toBe(29);
});
test('get statistics from a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 101 }))[0];
await job.annotations.clear(true);
const statistics = await job.annotations.statistics();
expect(statistics).toBeInstanceOf(window.cvat.classes.Statistics);
expect(statistics.total.total).toBe(512);
});
});
describe('Feature: select object', () => {
test('select object in a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
let result = await task.annotations.select(annotations, 1430, 765);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.RECTANGLE);
result = await task.annotations.select(annotations, 1415, 765);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.POLYGON);
expect(result.state.points.length).toBe(10);
result = await task.annotations.select(annotations, 1083, 543);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.POINTS);
expect(result.state.points.length).toBe(16);
result = await task.annotations.select(annotations, 613, 811);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.POLYGON);
expect(result.state.points.length).toBe(94);
});
test('select object in a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const annotations = await job.annotations.get(0);
let result = await job.annotations.select(annotations, 490, 540);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.RECTANGLE);
result = await job.annotations.select(annotations, 430, 260);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.POLYLINE);
result = await job.annotations.select(annotations, 1473, 250);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.RECTANGLE);
result = await job.annotations.select(annotations, 1490, 237);
expect(result.state.shapeType).toBe(window.cvat.enums.ObjectShape.POLYGON);
expect(result.state.points.length).toBe(94);
});
test('trying to select from not object states', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
expect(task.annotations.select(annotations.concat({}), 500, 500))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to select with invalid coordinates', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
expect(task.annotations.select(annotations, null, null))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
expect(task.annotations.select(annotations, null, null))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
expect(task.annotations.select(annotations, '5', '10'))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
/* global
require:false
jest:false
describe:false
*/
// Setup mock for a server
jest.mock('../../src/server-proxy', () => {
const mock = require('../mocks/server-proxy.mock');
return mock;
});
// Initialize api
require('../../src/api');
const { FrameData } = require('../../src/frames');
describe('Feature: get frame meta', () => {
test('get meta for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const frame = await task.frames.get(0);
expect(frame).toBeInstanceOf(FrameData);
});
test('get meta for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const frame = await job.frames.get(0);
expect(frame).toBeInstanceOf(FrameData);
});
test('pass frame number out of a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
expect(task.frames.get(100))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
expect(task.frames.get(-1))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('pass bad frame number', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
expect(task.frames.get('5'))
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('do not pass any frame number', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
expect(task.frames.get())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: get frame data', () => {
test('get frame data for a task', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const frame = await task.frames.get(0);
const frameData = await frame.data();
expect(typeof (frameData)).toBe('string');
});
test('get frame data for a job', async () => {
const job = (await window.cvat.jobs.get({ jobID: 100 }))[0];
const frame = await job.frames.get(0);
const frameData = await frame.data();
expect(typeof (frameData)).toBe('string');
});
});
......@@ -64,26 +64,26 @@ describe('Feature: get a list of jobs', () => {
});
test('get jobs by invalid filter with both taskID and jobID', async () => {
await expect(window.cvat.jobs.get({
expect(window.cvat.jobs.get({
taskID: 1,
jobID: 1,
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('get jobs by invalid job id', async () => {
await expect(window.cvat.jobs.get({
expect(window.cvat.jobs.get({
jobID: '1',
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('get jobs by invalid task id', async () => {
await expect(window.cvat.jobs.get({
expect(window.cvat.jobs.get({
taskID: '1',
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('get jobs by unknown filter', async () => {
await expect(window.cvat.jobs.get({
expect(window.cvat.jobs.get({
unknown: 50,
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
......
/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
/* global
require:false
jest:false
describe:false
*/
// Setup mock for a server
jest.mock('../../src/server-proxy', () => {
const mock = require('../mocks/server-proxy.mock');
return mock;
});
// Initialize api
require('../../src/api');
describe('Feature: set attributes for an object state', () => {
test('set a valid value', () => {
const state = new window.cvat.classes.ObjectState({
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
frame: 5,
});
const attributes = {
5: 'man',
6: 'glasses',
};
state.attributes = attributes;
expect(state.attributes).toEqual(attributes);
});
test('trying to set a bad value', () => {
const state = new window.cvat.classes.ObjectState({
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
frame: 5,
});
let attributes = 'bad attribute';
expect(() => {
state.attributes = attributes;
}).toThrow(window.cvat.exceptions.ArgumentError);
attributes = 5;
expect(() => {
state.attributes = attributes;
}).toThrow(window.cvat.exceptions.ArgumentError);
attributes = false;
expect(() => {
state.attributes = attributes;
}).toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: set points for an object state', () => {
test('set a valid value', () => {
const state = new window.cvat.classes.ObjectState({
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
frame: 5,
});
const points = [1, 2, 3, 4];
state.points = points;
expect(state.points).toEqual(points);
});
test('trying to set a bad value', () => {
const state = new window.cvat.classes.ObjectState({
objectType: window.cvat.enums.ObjectType.SHAPE,
shapeType: window.cvat.enums.ObjectShape.RECTANGLE,
frame: 5,
});
let points = 'bad points';
expect(() => {
state.points = points;
}).toThrow(window.cvat.exceptions.ArgumentError);
points = 5;
expect(() => {
state.points = points;
}).toThrow(window.cvat.exceptions.ArgumentError);
points = false;
expect(() => {
state.points = points;
}).toThrow(window.cvat.exceptions.ArgumentError);
points = {};
expect(() => {
state.points = points;
}).toThrow(window.cvat.exceptions.ArgumentError);
});
});
describe('Feature: save object from its state', () => {
test('save valid values for a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
let state = annotations[0];
expect(state.objectType).toBe(window.cvat.enums.ObjectType.SHAPE);
expect(state.shapeType).toBe(window.cvat.enums.ObjectShape.RECTANGLE);
state.points = [0, 0, 100, 100];
state.occluded = true;
[, state.label] = task.labels;
state.lock = true;
state = await state.save();
expect(state).toBeInstanceOf(window.cvat.classes.ObjectState);
expect(state.label.id).toBe(task.labels[1].id);
expect(state.lock).toBe(true);
expect(state.occluded).toBe(true);
expect(state.points).toEqual([0, 0, 100, 100]);
});
test('save valid values for a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(10);
let state = annotations[1];
expect(state.objectType).toBe(window.cvat.enums.ObjectType.TRACK);
expect(state.shapeType).toBe(window.cvat.enums.ObjectShape.RECTANGLE);
state.occluded = true;
state.lock = true;
state.points = [100, 200, 200, 400];
state.attributes = {
1: 'sitting',
3: 'female',
2: '10',
4: 'true',
};
state = await state.save();
expect(state).toBeInstanceOf(window.cvat.classes.ObjectState);
expect(state.lock).toBe(true);
expect(state.occluded).toBe(true);
expect(state.points).toEqual([100, 200, 200, 400]);
expect(state.attributes[1]).toBe('sitting');
expect(state.attributes[2]).toBe('10');
expect(state.attributes[3]).toBe('female');
expect(state.attributes[4]).toBe('true');
state.lock = false;
[state.label] = task.labels;
state = await state.save();
expect(state.label.id).toBe(task.labels[0].id);
state.outside = true;
state = await state.save();
expect(state.lock).toBe(false);
expect(state.outside).toBe(true);
state.keyframe = false;
state = await state.save();
expect(state.keyframe).toBe(false);
});
test('save bad values for a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
state.occluded = 'false';
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
const oldPoints = state.points;
state.occluded = false;
state.points = ['100', '50', '100', {}];
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.points = oldPoints;
state.lock = 'true';
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
const oldLabel = state.label;
state.lock = false;
state.label = 1;
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.label = oldLabel;
state.attributes = { 1: {}, 2: false, 3: () => {} };
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('save bad values for a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
state.occluded = 'false';
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
const oldPoints = state.points;
state.occluded = false;
state.points = ['100', '50', '100', {}];
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.points = oldPoints;
state.lock = 'true';
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
const oldLabel = state.label;
state.lock = false;
state.label = 1;
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.label = oldLabel;
state.outside = 5;
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.outside = false;
state.keyframe = '10';
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
state.keyframe = true;
state.attributes = { 1: {}, 2: false, 3: () => {} };
await expect(state.save())
.rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('trying to change locked shape', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
let state = annotations[0];
state.lock = true;
state = await state.save();
const { points } = state;
state.points = [0, 0, 500, 500];
state = await state.save();
expect(state.points).toEqual(points);
});
test('trying to set too small area of a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
let state = annotations[0];
const { points } = state;
state.points = [0, 0, 2, 2]; // area is 4
state = await state.save();
expect(state.points).toEqual(points);
});
test('trying to set too small area of a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
let state = annotations[0];
const { points } = state;
state.points = [0, 0, 2, 2]; // area is 4
state = await state.save();
expect(state.points).toEqual(points);
});
test('trying to set too small length of a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
let state = annotations[8];
const { points } = state;
state.points = [0, 0, 2, 2]; // length is 2
state = await state.save();
expect(state.points).toEqual(points);
});
});
describe('Feature: delete object', () => {
test('delete a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotationsBefore = await task.annotations.get(0);
const { length } = annotationsBefore;
await annotationsBefore[0].delete();
const annotationsAfter = await task.annotations.get(0);
expect(annotationsAfter).toHaveLength(length - 1);
});
test('delete a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotationsBefore = await task.annotations.get(0);
const { length } = annotationsBefore;
await annotationsBefore[0].delete();
const annotationsAfter = await task.annotations.get(0);
expect(annotationsAfter).toHaveLength(length - 1);
});
});
describe('Feature: change z order of an object', () => {
test('up z order for a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
const { zOrder } = state;
await state.up();
expect(state.zOrder).toBeGreaterThan(zOrder);
});
test('up z order for a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
const { zOrder } = state;
await state.up();
expect(state.zOrder).toBeGreaterThan(zOrder);
});
test('down z order for a shape', async () => {
const task = (await window.cvat.tasks.get({ id: 100 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
const { zOrder } = state;
await state.down();
expect(state.zOrder).toBeLessThan(zOrder);
});
test('down z order for a track', async () => {
const task = (await window.cvat.tasks.get({ id: 101 }))[0];
const annotations = await task.annotations.get(0);
const state = annotations[0];
const { zOrder } = state;
await state.down();
expect(state.zOrder).toBeLessThan(zOrder);
});
});
/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
/* global
require:false
jest:false
describe:false
*/
// Setup mock for a server
jest.mock('../../src/server-proxy', () => {
const mock = require('../mocks/server-proxy.mock');
return mock;
});
// Initialize api
require('../../src/api');
describe('Feature: dummy feature', () => {
test('dummy test', async () => {
// TODO: Write test after design of plugin system
});
});
/*
const plugin = {
name: 'Example Plugin',
description: 'This example plugin demonstrates how plugin system in CVAT works',
cvat: {
server: {
about: {
async leave(self, result) {
result.plugins = await self.internal.getPlugins();
return result;
},
},
},
classes: {
Job: {
prototype: {
annotations: {
put: {
enter(self, objects) {
for (const obj of objects) {
if (obj.type !== 'tag') {
const points = obj.position.map((point) => {
const roundPoint = {
x: Math.round(point.x),
y: Math.round(point.y),
};
return roundPoint;
});
obj.points = points;
}
}
},
},
},
},
},
},
},
internal: {
async getPlugins() {
const plugins = await window.cvat.plugins.list();
return plugins.map((el) => {
const obj = {
name: el.name,
description: el.description,
};
return obj;
});
},
},
};
async function test() {
await window.cvat.plugins.register(plugin);
await window.cvat.server.login('admin', 'nimda760');
try {
console.log(JSON.stringify(await window.cvat.server.about()));
console.log(await window.cvat.users.get({ self: false }));
console.log(await window.cvat.users.get({ self: true }));
console.log(JSON.stringify(await window.cvat.jobs.get({ taskID: 8 })));
console.log(JSON.stringify(await window.cvat.jobs.get({ jobID: 10 })));
console.log(await window.cvat.tasks.get());
console.log(await window.cvat.tasks.get({ id: 8 }));
console.log('Done.');
} catch (exception) {
console.log(exception.constructor.name);
console.log(exception.message);
}
}
*/
......@@ -44,7 +44,7 @@ describe('Feature: get share storage info', () => {
});
test('get files in a some unknown dir of a share storage', async () => {
await expect(window.cvat.server.share(
expect(window.cvat.server.share(
'Unknown Directory',
)).rejects.toThrow(window.cvat.exceptions.ServerError);
});
......
......@@ -26,7 +26,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(3);
expect(result).toHaveLength(5);
for (const el of result) {
expect(el).toBeInstanceOf(Task);
}
......@@ -51,7 +51,7 @@ describe('Feature: get a list of tasks', () => {
});
test('get a task by an invalid id', async () => {
await expect(window.cvat.tasks.get({
expect(window.cvat.tasks.get({
id: '50',
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
......@@ -61,7 +61,7 @@ describe('Feature: get a list of tasks', () => {
mode: 'interpolation',
});
expect(Array.isArray(result)).toBeTruthy();
expect(result).toHaveLength(2);
expect(result).toHaveLength(3);
for (const el of result) {
expect(el).toBeInstanceOf(Task);
expect(el.mode).toBe('interpolation');
......@@ -69,7 +69,7 @@ describe('Feature: get a list of tasks', () => {
});
test('get tasks by invalid filters', async () => {
await expect(window.cvat.tasks.get({
expect(window.cvat.tasks.get({
unknown: '5',
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
......@@ -184,77 +184,3 @@ describe('Feature: delete a task', () => {
expect(result).toHaveLength(0);
});
});
/*
const plugin = {
name: 'Example Plugin',
description: 'This example plugin demonstrates how plugin system in CVAT works',
cvat: {
server: {
about: {
async leave(self, result) {
result.plugins = await self.internal.getPlugins();
return result;
},
},
},
classes: {
Job: {
prototype: {
annotations: {
put: {
enter(self, objects) {
for (const obj of objects) {
if (obj.type !== 'tag') {
const points = obj.position.map((point) => {
const roundPoint = {
x: Math.round(point.x),
y: Math.round(point.y),
};
return roundPoint;
});
obj.points = points;
}
}
},
},
},
},
},
},
},
internal: {
async getPlugins() {
const plugins = await window.cvat.plugins.list();
return plugins.map((el) => {
const obj = {
name: el.name,
description: el.description,
};
return obj;
});
},
},
};
async function test() {
await window.cvat.plugins.register(plugin);
await window.cvat.server.login('admin', 'nimda760');
try {
console.log(JSON.stringify(await window.cvat.server.about()));
console.log(await window.cvat.users.get({ self: false }));
console.log(await window.cvat.users.get({ self: true }));
console.log(JSON.stringify(await window.cvat.jobs.get({ taskID: 8 })));
console.log(JSON.stringify(await window.cvat.jobs.get({ jobID: 10 })));
console.log(await window.cvat.tasks.get());
console.log(await window.cvat.tasks.get({ id: 8 }));
console.log('Done.');
} catch (exception) {
console.log(exception.constructor.name);
console.log(exception.message);
}
}
*/
......@@ -41,13 +41,13 @@ describe('Feature: get a list of users', () => {
});
test('get users with unknown filter key', async () => {
await expect(window.cvat.users.get({
expect(window.cvat.users.get({
unknown: '50',
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
test('get users with invalid filter key', async () => {
await expect(window.cvat.users.get({
expect(window.cvat.users.get({
self: 1,
})).rejects.toThrow(window.cvat.exceptions.ArgumentError);
});
......
......@@ -106,10 +106,436 @@ const shareDummyData = [
]
const tasksDummyData = {
"count": 3,
"count": 4,
"next": null,
"previous": null,
"results": [
{
"url": "http://localhost:7000/api/v1/tasks/1",
"id": 100,
"name": "Image Task",
"size": 9,
"mode": "annotation",
"owner": 1,
"assignee": null,
"bug_tracker": "",
"created_date": "2019-06-18T13:05:08.941304+03:00",
"updated_date": "2019-07-16T15:51:29.142871+03:00",
"overlap": 0,
"segment_size": 0,
"z_order": false,
"status": "annotation",
"labels": [
{
"id": 1,
"name": "car,",
"attributes": [
]
},
{
"id": 2,
"name": "person",
"attributes": [
]
}
],
"segments": [
{
"start_frame": 0,
"stop_frame": 8,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/1",
"id": 100,
"assignee": null,
"status": "annotation"
}
]
}
],
"image_quality": 50,
"start_frame": 0,
"stop_frame": 0,
"frame_filter": ""
},
{
"url": "http://localhost:7000/api/v1/tasks/10",
"id": 101,
"name": "Video Task",
"size": 5002,
"mode": "interpolation",
"owner": 1,
"assignee": null,
"bug_tracker": "",
"created_date": "2019-06-21T16:34:49.199691+03:00",
"updated_date": "2019-07-12T16:43:58.904892+03:00",
"overlap": 5,
"segment_size": 500,
"z_order": false,
"status": "annotation",
"labels": [
{
"id": 22,
"name": "bicycle",
"attributes":[
{
"id": 13,
"name": "driver",
"mutable": false,
"input_type": "radio",
"default_value": "man",
"values": [
"man",
"woman"
]
},
{
"id": 14,
"name": "sport",
"mutable": true,
"input_type": "checkbox",
"default_value": "false",
"values": [
"false"
]
}
]
},
{
"id": 21,
"name": "car",
"attributes": [
{
"id": 10,
"name": "model",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"bmw",
"mazda",
"suzuki",
"kia"
]
},
{
"id": 11,
"name": "driver",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"man",
"woman"
]
},
{
"id": 12,
"name": "parked",
"mutable": true,
"input_type": "checkbox",
"default_value": "true",
"values": [
"true"
]
}
]
},
{
"id": 20,
"name": "face",
"attributes": [
{
"id": 6,
"name": "age",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"skip",
"baby (0-5)",
"child (6-12)",
"adolescent (13-19)",
"adult (20-45)",
"middle-age (46-64)",
"old (65-)"
]
},
{
"id": 7,
"name": "glass",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"skip",
"no",
"sunglass",
"transparent",
"other"
]
},
{
"id": 8,
"name": "beard",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"skip",
"no",
"yes"
]
},
{
"id": 9,
"name": "race",
"mutable": false,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"skip",
"asian",
"black",
"caucasian",
"other"
]
}
]
},
{
"id": 23,
"name": "motorcycle",
"attributes": [
{
"id": 15,
"name": "model",
"mutable": false,
"input_type": "text",
"default_value": "unknown",
"values": [
"unknown"
]
}
]
},
{
"id": 19,
"name": "person, pedestrian",
"attributes": [
{
"id": 1,
"name": "action",
"mutable": true,
"input_type": "select",
"default_value": "__undefined__",
"values": [
"__undefined__",
"sitting",
"raising_hand",
"standing"
]
},
{
"id": 2,
"name": "age",
"mutable": false,
"input_type": "number",
"default_value": "1",
"values": [
"1",
"100",
"1"
]
},
{
"id": 3,
"name": "gender",
"mutable" :false,
"input_type": "select",
"default_value": "male",
"values": [
"male",
"female"
]
},
{
"id": 4,
"name": "false positive",
"mutable": false,
"input_type": "checkbox",
"default_value": "false",
"values": [
"false"
]
},
{
"id": 5,
"name": "clother",
"mutable": true,
"input_type": "text",
"default_value": "non, initialized",
"values": [
"non, initialized"
]
}
]
},
{
"id": 24,
"name": "road",
"attributes": [
]
}
],
"segments": [
{
"start_frame": 0,
"stop_frame": 499,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/10",
"id": 101,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 495,
"stop_frame": 994,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/11",
"id": 102,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 990,
"stop_frame": 1489,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/12",
"id": 103,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 1485,
"stop_frame": 1984,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/13",
"id": 104,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 1980,
"stop_frame": 2479,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/14",
"id": 105,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 2475,
"stop_frame": 2974,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/15",
"id": 106,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 2970,
"stop_frame": 3469,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/16",
"id": 107,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 3465,
"stop_frame": 3964,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/17",
"id": 108,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 3960,
"stop_frame": 4459,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/18",
"id": 109,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 4455,
"stop_frame": 4954,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/19",
"id": 110,
"assignee": null,
"status": "annotation"
}
]
},
{
"start_frame": 4950,
"stop_frame": 5001,
"jobs": [
{
"url": "http://localhost:7000/api/v1/jobs/20",
"id": 111,
"assignee": null,
"status": "annotation"
}
]
}
],
"image_quality": 50,
"start_frame": 0,
"stop_frame": 5001,
"frame_filter": ""
},
{
"url": "http://localhost:7000/api/v1/tasks/3",
"id": 3,
......@@ -881,9 +1307,1142 @@ const tasksDummyData = {
]
}
const taskAnnotationsDummyData = {
'101': {
"version":21,
"tags":[],
"shapes":[],
"tracks":[
{
"id": 25, // interpolation
"frame": 10,
"label_id": 19,
"group": 0,
"shapes": [{
"type": "polygon",
"occluded": false,
"z_order": 2,
"points": [
377.64912280702083,
458.5473684210556,
383.82456140351314,
458.5473684210556,
406.98245614035477,
455.45964912281124,
431.6842105263204,
455.45964912281124,
457.92982456140817,
455.45964912281124,
482.6315789473738,
455.45964912281124,
508.87719298246157,
455.45964912281124,
535.1228070175493,
455.45964912281124,
559.8245614035113,
455.45964912281124,
587.6140350877249,
455.45964912281124,
620.0350877193014,
455.45964912281124,
640.1052631578968,
455.45964912281124,
664.8070175438625,
453.9157894736891,
692.5964912280724,
450.8280701754411,
721.9298245614082,
450.8280701754411,
743.5438596491258,
447.74035087719676,
769.7894736842136,
446.1964912280746,
796.0350877193014,
446.1964912280746,
823.8245614035113,
446.1964912280746,
846.9824561403548,
446.1964912280746,
876.3157894736869,
446.1964912280746,
905.6491228070226,
446.1964912280746,
931.8947368421104,
446.1964912280746,
959.6842105263204,
446.1964912280746,
987.4736842105303,
446.1964912280746,
1015.2631578947403,
446.1964912280746,
1039.964912280706,
446.1964912280746,
1066.2105263157937,
446.1964912280746,
1090.9122807017593,
446.1964912280746,
1115.614035087725,
446.1964912280746,
1138.7719298245647,
449.28421052631893,
1231.4000000000015,
413.8000000000011,
1180.4561403508815,
467.81052631579223,
1180.4561403508815,
494.05614035088,
1180.4561403508815,
520.3017543859678,
1180.4561403508815,
545.0035087719334,
1180.4561403508815,
571.2491228070212,
1180.4561403508815,
597.494736842109,
1180.4561403508815,
620.6526315789524,
1180.4561403508815,
649.9859649122845,
1180.4561403508815,
676.2315789473723,
1180.4561403508815,
699.3894736842158,
1180.4561403508815,
727.1789473684257,
1180.4561403508815,
747.2491228070212,
1180.4561403508815,
771.9508771929868,
1180.4561403508815,
802.8280701754411,
1180.4561403508815,
830.6175438596547,
1180.4561403508815,
853.7754385964945,
1180.4561403508815,
880.0210526315823,
1183.5438596491258,
901.6350877193036,
1183.5438596491258,
929.4245614035135,
1186.6315789473738,
952.5824561403533,
1188.175438596496,
975.7403508771968,
1188.175438596496,
1001.9859649122845,
1188.175438596496,
1023.6000000000022,
1188.175438596496,
1057.5649122807044,
1186.6315789473738,
1082.26666666667,
1186.6315789473738,
1108.5122807017578,
1186.6315789473738,
1133.2140350877235,
1175.82421875,
1154.828125,
1155.7543859649159,
1156.371929824567,
1132.5964912280724,
1154.828070175441,
1106.3508771929846,
1154.828070175441,
1078.5614035087747,
1154.828070175441,
1053.8596491228127,
1150.1964912280746,
1030.7017543859693,
1148.6526315789524,
1002.9122807017593,
1148.6526315789524,
982.8421052631602,
1148.6526315789524,
953.5087719298281,
1147.1087719298303,
922.6315789473738,
1147.1087719298303,
891.7543859649159,
1147.1087719298303,
868.5964912280724,
1147.1087719298303,
839.2631578947403,
1147.1087719298303,
816.1052631578968,
1147.1087719298303,
786.7719298245647,
1147.1087719298303,
760.5263157894769,
1147.1087719298303,
735.8245614035113,
1147.1087719298303,
708.0350877193014,
1142.47719298246,
684.8771929824616,
1140.933333333338,
658.6315789473738,
1140.933333333338,
633.9298245614082,
1140.933333333338,
607.6842105263204,
1139.3894736842158,
581.4385964912326,
1134.7578947368456,
559.8245614035113,
1133.2140350877235,
535.1228070175493,
1131.6701754386013,
505.7894736842136,
1131.6701754386013,
482.6315789473738,
1131.6701754386013,
454.8421052631602,
1130.1263157894791,
430.1403508771964,
1130.1263157894791,
405.4385964912326,
1130.1263157894791,
383.82421875,
1130.126953125,
382.28070175438916,
1113.143859649128,
380.736842105267,
1088.4421052631624,
380.736842105267,
1056.0210526315823,
380.736842105267,
1026.6877192982502,
379.1929824561448,
1005.0736842105289,
374.5614035087765,
978.8280701754411,
371.47368421053034,
949.494736842109,
371.47368421053034,
921.705263157899,
371.47368421053034,
897.0035087719334,
371.47368421053034,
866.1263157894791,
371.47368421053034,
842.9684210526357,
371.47368421053034,
810.5473684210556,
371.47368421053034,
778.1263157894791,
377.64912280702083,
751.8807017543913,
380.736842105267,
722.5473684210556,
385.3684210526353,
693.2140350877235,
385.3684210526353,
668.5122807017578,
386.9122807017575,
643.8105263157922,
388.45614035088147,
619.1087719298266,
388.45614035088147,
591.3192982456167,
388.45614035088147,
563.5298245614067,
388.45614035088147,
535.7403508771968,
388.45614035088147,
511.03859649123115,
386.9122807017575,
487.88070175439134
],
"id":382,
"frame":10,
"outside":false,
"attributes": [{
"spec_id":1,
"value":"__undefined__"
}, {
"spec_id":5,
"value":"non, initialized"
}]
}, {
"type": "polygon",
"occluded": false,
"z_order": 2,
"points": [
502.701171875,
1093.07421875,
860.8771929824616,
443.10877192982844,
1462.9824561403548,
1120.8631578947425
],
"id": 383,
"frame": 20,
"outside": false,
"attributes": []
}, {
"type": "polygon",
"occluded": false,
"z_order": 2,
"points": [
502.701171875,
1093.07421875,
860.8771929824616,
443.10877192982844,
1462.9824561403548,
1120.8631578947425
],
"id": 384,
"frame": 22,
"outside": true,
"attributes": []
}],
"attributes": [{
"spec_id": 2,
"value": "1"
}, {
"spec_id": 3,
"value": "male"
}, {
"spec_id": 4,
"value": "false"
}]
},
{
"id": 60,
"frame": 0,
"label_id": 19,
"group": 0,
"shapes": [{
"type": "rectangle",
"occluded": false,
"z_order": 1,
"points": [
425.58984375,
540.298828125,
755.9765625,
745.6328125
],
"id": 379,
"frame": 0,
"outside": false,
"attributes": [
{
"spec_id":5,
"value":"non, initialized"
},
{
"spec_id":1,
"value":"__undefined__"
}
]
}, {
"type": "rectangle",
"occluded": false,
"z_order": 1,
"points": [
238.8000000000011,
498.6000000000022,
546.01171875,
660.720703125
],
"id": 380,
"frame": 10,
"outside": false,
"attributes": []
}, {
"type":"rectangle",
"occluded":false,
"z_order":1,
"points":[
13.3955078125,
447.650390625,
320.6072265624989,
609.7710937499978
],
"id":381,
"frame":20,
"outside":false,
"attributes":[
]
}],
"attributes":[
{
"spec_id":2,
"value":"1"
},
{
"spec_id":3,
"value":"male"
},
{
"spec_id":4,
"value":"false"
}]
}
]
},
'100': {
"version": 16,
"tags": [],
"shapes": [{
"type": "rectangle",
"occluded": false,
"z_order": 1,
"points": [
387.91,
403.81,
595.14,
712.25
],
"id": 108,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 2,
"points": [
783.12,
368.91,
990.35,
677.34
],
"id": 109,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 3,
"points": [
1277.1,
239.99,
1484.33,
548.43
],
"id": 110,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 4,
"points": [
1420.48,
713.49,
1627.71,
1021.92
],
"id": 111,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes":[
]
}, {
"type": "rectangle",
"occluded": false,
"z_order": 5,
"points": [
896.38,
659.27,
1103.61,
967.71
],
"id": 112,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "polygon",
"occluded": false,
"z_order": 6,
"points": [
449.36,
892.97,
449.36,
892.97,
468.63,
913.46,
495.14,
933.94,
527.67,
955.62,
562.61,
973.7,
589.12,
983.34,
613.21,
988.15,
632.49,
991.77,
656.59,
994.18,
686.71,
994.18,
733.69,
980.93,
772.25,
959.24,
809.6,
927.91,
837.31,
896.59,
851.77,
867.67,
861.41,
841.17,
862.61,
805.02,
840.92,
759.24,
802.37,
720.68,
777.07,
703.82,
750.56,
690.56,
726.47,
684.54,
698.75,
680.92,
681.89,
680.92,
656.59,
680.92,
633.69,
683.33,
608.39,
690.56,
578.27,
706.22,
548.15,
718.27,
518.03,
730.32,
486.71,
743.57,
458.99,
756.83,
434.9,
766.47,
408.39,
777.31,
381.89,
786.95,
354.17,
794.18,
331.28,
800.2,
295.14,
803.82,
283.09,
800.2,
267.43,
783.33,
255.38,
766.47,
232.49,
733.94,
220.44,
713.45,
212.0,
688.15,
208.39,
666.47,
210.8,
647.19
],
"id": 113,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes":[]
}, {
"type": "polygon",
"occluded": false,
"z_order": 7,
"points": [
1260.84,
344.81,
1260.84,
344.81,
1280.11,
365.29,
1306.62,
385.78,
1339.15,
407.46,
1374.09,
425.53,
1400.6,
435.17,
1424.69,
439.99,
1443.97,
443.61,
1468.07,
446.02,
1498.19,
446.02,
1545.18,
432.76,
1583.73,
411.08,
1621.08,
379.75,
1648.79,
348.43,
1663.25,
319.51,
1672.89,
293.0,
1674.09,
256.86,
1652.41,
211.08,
1613.85,
172.52,
1588.55,
155.65,
1562.04,
142.4,
1537.95,
136.38,
1510.24,
132.76,
1493.37,
132.76,
1468.07,
132.76,
1445.18,
135.17,
1419.87,
142.4,
1389.75,
158.06,
1359.63,
170.11,
1329.51,
182.16,
1298.19,
195.41,
1270.48,
208.67,
1246.38,
218.3,
1219.87,
229.15,
1193.37,
238.79,
1165.66,
246.02,
1142.76,
252.04,
1106.62,
255.65,
1094.57,
252.04,
1078.91,
235.17,
1066.86,
218.3,
1043.97,
185.77,
1031.92,
165.29,
1023.49,
139.99,
1019.87,
118.3,
1022.28,
99.03
],
"id": 114,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "polygon",
"occluded": false,
"z_order": 8,
"points": [
1113.21,
723.09,
1322.86,
1018.28,
1562.62,
873.7,
1587.92,
641.16,
1267.43,
530.32
],
"id": 115,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "polyline",
"occluded": false,
"z_order": 9,
"points": [
268.63,
359.23,
277.07,
344.78,
292.73,
325.5,
312.01,
311.04,
331.28,
300.2,
349.36,
295.38,
375.86,
290.56,
387.91,
290.56,
418.03,
290.56,
439.72,
292.97,
457.79,
295.38,
492.73,
301.4,
525.26,
306.22,
534.9,
306.22,
571.04,
296.58,
591.53,
284.54,
610.8,
272.49,
640.92,
253.21,
655.38,
238.75
],
"id": 116,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "points",
"occluded": false,
"z_order": 10,
"points": [
1089.12,
505.02,
1178.28,
543.57,
1074.66,
602.61,
1109.6,
680.92,
1172.25,
631.53,
1036.11,
576.1,
1057.79,
445.98,
1185.51,
400.2
],
"id": 117,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": [
]
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1565.03,
555.62,
1787.92,
765.26
],
"id": 118,
"frame": 0,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 0,
"points": [
0.0,
0.0,
100.0,
100.0
],
"id": 119,
"frame": 1,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "polygon",
"occluded": false,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
0.0,
100.0,
200.0
],
"id": 120,
"frame": 1,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 121,
"frame": 1,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 122,
"frame": 1,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 123,
"frame": 2,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 124,
"frame": 2,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 125,
"frame": 3,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 126,
"frame": 3,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 127,
"frame": 4,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 128,
"frame": 4,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 129,
"frame": 5,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 130,
"frame": 5,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 131,
"frame": 6,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 132,
"frame": 6,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 133,
"frame": 7,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 134,
"frame": 7,
"label_id": 2,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": false,
"z_order": 11,
"points": [
1211.6,
500.48,
1434.49,
710.12
],
"id": 135,
"frame": 8,
"label_id": 1,
"group": 0,
"attributes": []
}, {
"type": "rectangle",
"occluded": true,
"z_order": 0,
"points": [
0.0,
0.0,
200.0,
200.0
],
"id": 136,
"frame": 8,
"label_id": 2,
"group": 0,
"attributes": []
}],
"tracks":[]
}
};
const jobAnnotationsDummyData = JSON.parse(JSON.stringify(taskAnnotationsDummyData));
const frameMetaDummyData = {
1: [{
"width": 1920,
"height": 1080
}, {
"width": 1600,
"height": 1143
}, {
"width": 1600,
"height": 859
}, {
"width": 3840,
"height": 2160
}, {
"width": 2560,
"height": 1920
}, {
"width": 1920,
"height": 1080
}, {
"width": 1920,
"height": 1080
}, {
"width": 700,
"height": 453
}, {
"width": 1920,
"height": 1200
}],
2: [{
"width": 1920,
"height": 1080
}],
3: [{
"width": 1888,
"height": 1408
}],
100: [{
"width": 1920,
"height": 1080
}, {
"width": 1600,
"height": 1143
}, {
"width": 1600,
"height": 859
}, {
"width": 3840,
"height": 2160
}, {
"width": 2560,
"height": 1920
}, {
"width": 1920,
"height": 1080
}, {
"width": 1920,
"height": 1080
}, {
"width": 700,
"height": 453
}, {
"width": 1920,
"height": 1200
}],
101: [{
"width": 1888,
"height": 1408
}],
}
module.exports = {
tasksDummyData,
aboutDummyData,
shareDummyData,
usersDummyData,
}
\ No newline at end of file
taskAnnotationsDummyData,
jobAnnotationsDummyData,
frameMetaDummyData,
}
......@@ -14,6 +14,9 @@ const {
aboutDummyData,
shareDummyData,
usersDummyData,
taskAnnotationsDummyData,
jobAnnotationsDummyData,
frameMetaDummyData,
} = require('./dummy-data.mock');
......@@ -185,19 +188,50 @@ class ServerProxy {
return JSON.parse(JSON.stringify(usersDummyData)).results[0];
}
async function getFrame() {
return null;
async function getData() {
return 'DUMMY_IMAGE';
}
async function getMeta() {
return null;
async function getMeta(tid) {
return JSON.parse(JSON.stringify(frameMetaDummyData[tid]));
}
async function getAnnotations() {
async function getAnnotations(session, id) {
if (session === 'task') {
return JSON.parse(JSON.stringify(taskAnnotationsDummyData[id]));
}
if (session === 'job') {
return JSON.parse(JSON.stringify(jobAnnotationsDummyData[id]));
}
return null;
}
async function updateAnnotations() {
async function updateAnnotations(session, id, data, action) {
// Actually we do not change our dummy data
// We just update the argument in some way and return it
data.version += 1;
if (action === 'create') {
let idGenerator = 1000;
data.tracks.concat(data.tags).concat(data.shapes).map((el) => {
el.id = ++idGenerator;
return el;
});
return data;
}
if (action === 'update') {
return data;
}
if (action === 'delete') {
return data;
}
return null;
}
......@@ -241,7 +275,7 @@ class ServerProxy {
frames: {
value: Object.freeze({
getFrame,
getData,
getMeta,
}),
writable: false,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册