Refactoring: add tools to endpoint testing

This commit is contained in:
IRBorisov 2024-03-23 20:53:23 +03:00
parent a47d93a59b
commit b549580452
10 changed files with 524 additions and 642 deletions

View File

@ -1,12 +1,12 @@
''' Models: RSForm API. ''' ''' Models: RSForm API. '''
from typing import Dict, Iterable, Optional, cast from typing import Dict, Iterable, Optional, Union, cast
from django.db import transaction from django.db import transaction
from django.db.models import QuerySet from django.db.models import QuerySet
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from cctext import Resolver, Entity, extract_entities, split_grams, TermForm from cctext import Resolver, Entity, extract_entities, split_grams, TermForm
from .api_RSLanguage import get_type_prefix, generate_structure from .api_RSLanguage import get_type_prefix, generate_structure, guess_type
from .LibraryItem import LibraryItem, LibraryItemType from .LibraryItem import LibraryItem, LibraryItemType
from .Constituenta import CstType, Constituenta from .Constituenta import CstType, Constituenta
from .Version import Version from .Version import Version
@ -90,18 +90,27 @@ class RSForm:
return result return result
@transaction.atomic @transaction.atomic
def insert_new(self, alias: str, insert_type: CstType, position: int = _INSERT_LAST) -> Constituenta: def insert_new(
self,
alias: str,
cst_type: Union[CstType, None] = None,
position: int = _INSERT_LAST,
**kwargs
) -> Constituenta:
''' Insert new constituenta at given position. ''' Insert new constituenta at given position.
All following constituents order is shifted by 1 position. ''' All following constituents order is shifted by 1 position. '''
if self.constituents().filter(alias=alias).exists(): if self.constituents().filter(alias=alias).exists():
raise ValidationError(msg.aliasTaken(alias)) raise ValidationError(msg.aliasTaken(alias))
position = self._get_insert_position(position) position = self._get_insert_position(position)
if cst_type is None:
cst_type = guess_type(alias)
self._shift_positions(position, 1) self._shift_positions(position, 1)
result = Constituenta.objects.create( result = Constituenta.objects.create(
schema=self.item, schema=self.item,
order=position, order=position,
alias=alias, alias=alias,
cst_type=insert_type cst_type=cst_type,
**kwargs
) )
self.item.save() self.item.save()
result.refresh_from_db() result.refresh_from_db()

View File

@ -1,6 +1,6 @@
''' Models: Definitions and utility function for RSLanguage. ''' ''' Models: Definitions and utility function for RSLanguage. '''
import json import json
from typing import Tuple from typing import Tuple, cast
from enum import IntEnum , unique from enum import IntEnum , unique
from django.db.models import TextChoices from django.db.models import TextChoices
@ -54,6 +54,14 @@ def get_type_prefix(cst_type: CstType) -> str:
return 'T' return 'T'
return 'X' return 'X'
def guess_type(alias: str) -> CstType:
''' Get CstType for alias. '''
prefix = alias[0]
for (value, _) in CstType.choices:
if prefix == get_type_prefix(cast(CstType, value)):
return cast(CstType, value)
return CstType.BASE
def _get_structure_prefix(alias: str, expression: str, parse: dict) -> Tuple[str, str]: def _get_structure_prefix(alias: str, expression: str, parse: dict) -> Tuple[str, str]:
''' Generate prefix and alias for structure generation. ''' ''' Generate prefix and alias for structure generation. '''
args = parse['args'] args = parse['args']

View File

@ -0,0 +1,140 @@
''' Utils: base tester class for endpoints. '''
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status
from apps.users.models import User
def decl_endpoint(endpoint: str, method: str):
''' Decorator for EndpointTester methods to provide API attributes. '''
def set_endpoint_inner(function):
def wrapper(*args, **kwargs):
if '{' in endpoint:
args[0].endpoint = 'UNRESOLVED'
args[0].endpoint_mask = endpoint
else:
args[0].endpoint_mask = None
args[0].endpoint = endpoint
args[0].method = method
return function(*args, **kwargs)
return wrapper
return set_endpoint_inner
class EndpointTester(APITestCase):
''' Abstract base class for Testing endpoints. '''
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def toggle_staff(self, value: bool = True):
self.user.is_staff = value
self.user.save()
def login(self):
self.client.force_authenticate(user=self.user)
def logout(self):
self.client.logout()
def set_params(self, **kwargs):
''' Given named argument values resolve current endpoint_mask. '''
if self.endpoint_mask and len(kwargs) > 0:
self.endpoint = _resolve_url(self.endpoint_mask, **kwargs)
def get(self, endpoint: str = '', **kwargs):
if endpoint != '':
return self.client.get(endpoint)
else:
self.set_params(**kwargs)
return self.client.get(self.endpoint)
def post(self, data=None, **kwargs):
self.set_params(**kwargs)
if not data is None:
return self.client.post(self.endpoint, data=data, format='json')
else:
return self.client.post(self.endpoint)
def patch(self, data=None, **kwargs):
self.set_params(**kwargs)
if not data is None:
return self.client.patch(self.endpoint, data=data, format='json')
else:
return self.client.patch(self.endpoint)
def put(self, data, **kwargs):
self.set_params(**kwargs)
return self.client.get(self.endpoint, data=data, format='json')
def delete(self, data=None, **kwargs):
self.set_params(**kwargs)
if not data is None:
return self.client.delete(self.endpoint, data=data, format='json')
else:
return self.client.delete(self.endpoint)
def assertOK(self, data=None, **kwargs):
response = self.execute(data, **kwargs)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def assertBadData(self, data=None, **kwargs):
response = self.execute(data, **kwargs)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def assertForbidden(self, data=None, **kwargs):
response = self.execute(data, **kwargs)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def assertNotModified(self, data=None, **kwargs):
response = self.execute(data, **kwargs)
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
def assertNotFound(self, data=None, **kwargs):
response = self.execute(data, **kwargs)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def execute(self, data=None, **kwargs):
if self.method == 'get':
return self.get(**kwargs)
if self.method == 'post':
return self.post(data, **kwargs)
if self.method == 'put':
return self.put(data, **kwargs)
if self.method == 'patch':
return self.patch(data, **kwargs)
if self.method == 'delete':
return self.delete(data, **kwargs)
return None
def _resolve_url(url: str, **kwargs) -> str:
if url == '' or len(kwargs) == 0:
return url
pos_input: int = 0
pos_start: int = 0
pos_end: int = 0
arg_names = set()
output: str = ''
while True:
pos_start = url.find('{', pos_input)
if pos_start == -1:
break
pos_end = url.find('}', pos_start)
if pos_end == -1:
break
name = url[(pos_start + 1) : pos_end]
arg_names.add(name)
if not name in kwargs:
raise KeyError(f'Missing argument: {name} | Mask: {url}')
output += url[pos_input : pos_start]
output += str(kwargs[name])
pos_input = pos_end + 1
if pos_input < len(url):
output += url[pos_input : len(url)]
for (key, _) in kwargs.items():
if key not in arg_names:
raise KeyError(f'Unused argument: {name} | Mask: {url}')
return output

View File

@ -1,63 +1,34 @@
''' Testing views ''' ''' Testing views '''
import os
import io
from zipfile import ZipFile
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework.exceptions import ErrorDetail
from rest_framework import status from rest_framework import status
from cctext import ReferenceType, split_grams from cctext import split_grams
from apps.users.models import User from .EndpointTester import decl_endpoint, EndpointTester
from apps.rsform.models import (
RSForm, Constituenta, CstType,
LibraryItem, LibraryItemType, Subscription, LibraryTemplate
)
from apps.rsform.views import (
convert_to_ascii,
convert_to_math,
parse_expression,
inflect,
parse_text,
generate_lexeme
)
class TestNaturalLanguageViews(APITestCase): class TestNaturalLanguageViews(EndpointTester):
def setUp(self): ''' Test natural language endpoints. '''
self.factory = APIRequestFactory()
self.client = APIClient()
def _assert_tags(self, actual: str, expected: str): def _assert_tags(self, actual: str, expected: str):
self.assertEqual(set(split_grams(actual)), set(split_grams(expected))) self.assertEqual(set(split_grams(actual)), set(split_grams(expected)))
@decl_endpoint(endpoint='/api/cctext/parse', method='post')
def test_parse_text(self): def test_parse_text(self):
data = {'text': 'синим слонам'} data = {'text': 'синим слонам'}
request = self.factory.post( response = self.execute(data)
'/api/cctext/parse',
data=data, format='json'
)
response = parse_text(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc') self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
@decl_endpoint(endpoint='/api/cctext/inflect', method='post')
def test_inflect(self): def test_inflect(self):
data = {'text': 'синий слон', 'grams': 'plur,datv'} data = {'text': 'синий слон', 'grams': 'plur,datv'}
request = self.factory.post( response = self.execute(data)
'/api/cctext/inflect',
data=data, format='json'
)
response = inflect(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], 'синим слонам') self.assertEqual(response.data['result'], 'синим слонам')
@decl_endpoint(endpoint='/api/cctext/generate-lexeme', method='post')
def test_generate_lexeme(self): def test_generate_lexeme(self):
data = {'text': 'синий слон'} data = {'text': 'синий слон'}
request = self.factory.post( response = self.execute(data)
'/api/cctext/generate-lexeme',
data=data, format='json'
)
response = generate_lexeme(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['items']), 12) self.assertEqual(len(response.data['items']), 12)
self.assertEqual(response.data['items'][0]['text'], 'синий слон') self.assertEqual(response.data['items'][0]['text'], 'синий слон')

View File

@ -1,22 +1,20 @@
''' Testing API: Constituents. ''' ''' Testing API: Constituents. '''
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status from rest_framework import status
from apps.users.models import User
from apps.rsform.models import RSForm, Constituenta, CstType from apps.rsform.models import RSForm, Constituenta, CstType
from .EndpointTester import decl_endpoint, EndpointTester
class TestConstituentaAPI(APITestCase):
class TestConstituentaAPI(EndpointTester):
''' Testing Constituenta view. ''' ''' Testing Constituenta view. '''
def setUp(self): def setUp(self):
self.factory = APIRequestFactory() super().setUp()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.rsform_owned = RSForm.create(title='Test', alias='T1', owner=self.user) self.rsform_owned = RSForm.create(title='Test', alias='T1', owner=self.user)
self.rsform_unowned = RSForm.create(title='Test2', alias='T2') self.rsform_unowned = RSForm.create(title='Test2', alias='T2')
self.cst1 = Constituenta.objects.create( self.cst1 = Constituenta.objects.create(
alias='X1', alias='X1',
cst_type=CstType.BASE,
schema=self.rsform_owned.item, schema=self.rsform_owned.item,
order=1, order=1,
convention='Test', convention='Test',
@ -25,6 +23,7 @@ class TestConstituentaAPI(APITestCase):
term_forms=[{'text':'form1', 'tags':'sing,datv'}]) term_forms=[{'text':'form1', 'tags':'sing,datv'}])
self.cst2 = Constituenta.objects.create( self.cst2 = Constituenta.objects.create(
alias='X2', alias='X2',
cst_type=CstType.BASE,
schema=self.rsform_unowned.item, schema=self.rsform_unowned.item,
order=1, order=1,
convention='Test1', convention='Test1',
@ -40,51 +39,40 @@ class TestConstituentaAPI(APITestCase):
definition_raw='Test1', definition_raw='Test1',
definition_resolved='Test2' definition_resolved='Test2'
) )
self.invalid_cst = self.cst3.pk + 1337
@decl_endpoint('/api/constituents/{item}', method='get')
def test_retrieve(self): def test_retrieve(self):
response = self.client.get(f'/api/constituents/{self.cst1.id}') self.assertNotFound(item=self.invalid_cst)
response = self.execute(item=self.cst1.id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['alias'], self.cst1.alias) self.assertEqual(response.data['alias'], self.cst1.alias)
self.assertEqual(response.data['convention'], self.cst1.convention) self.assertEqual(response.data['convention'], self.cst1.convention)
@decl_endpoint('/api/constituents/{item}', method='patch')
def test_partial_update(self): def test_partial_update(self):
data = {'convention': 'tt'} data = {'convention': 'tt'}
response = self.client.patch( self.assertForbidden(data, item=self.cst2.id)
f'/api/constituents/{self.cst2.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.client.logout() self.logout()
response = self.client.patch( self.assertForbidden(data, item=self.cst1.id)
f'/api/constituents/{self.cst1.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.client.force_authenticate(user=self.user) self.login()
response = self.client.patch( response = self.execute(data, item=self.cst1.id)
f'/api/constituents/{self.cst1.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.cst1.refresh_from_db() self.cst1.refresh_from_db()
self.assertEqual(response.data['convention'], 'tt') self.assertEqual(response.data['convention'], 'tt')
self.assertEqual(self.cst1.convention, 'tt') self.assertEqual(self.cst1.convention, 'tt')
response = self.client.patch( self.assertOK(data, item=self.cst1.id)
f'/api/constituents/{self.cst1.id}',
data=data,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
@decl_endpoint('/api/constituents/{item}', method='patch')
def test_update_resolved_no_refs(self): def test_update_resolved_no_refs(self):
data = { data = {
'term_raw': 'New term', 'term_raw': 'New term',
'definition_raw': 'New def' 'definition_raw': 'New def'
} }
response = self.client.patch(f'/api/constituents/{self.cst3.id}', data, format='json') response = self.execute(data, item=self.cst3.id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.cst3.refresh_from_db() self.cst3.refresh_from_db()
self.assertEqual(response.data['term_resolved'], 'New term') self.assertEqual(response.data['term_resolved'], 'New term')
@ -92,15 +80,13 @@ class TestConstituentaAPI(APITestCase):
self.assertEqual(response.data['definition_resolved'], 'New def') self.assertEqual(response.data['definition_resolved'], 'New def')
self.assertEqual(self.cst3.definition_resolved, 'New def') self.assertEqual(self.cst3.definition_resolved, 'New def')
@decl_endpoint('/api/constituents/{item}', method='patch')
def test_update_resolved_refs(self): def test_update_resolved_refs(self):
data = { data = {
'term_raw': '@{X1|nomn,sing}', 'term_raw': '@{X1|nomn,sing}',
'definition_raw': '@{X1|nomn,sing} @{X1|sing,datv}' 'definition_raw': '@{X1|nomn,sing} @{X1|sing,datv}'
} }
response = self.client.patch( response = self.execute(data, item=self.cst3.id)
f'/api/constituents/{self.cst3.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.cst3.refresh_from_db() self.cst3.refresh_from_db()
self.assertEqual(self.cst3.term_resolved, self.cst1.term_resolved) self.assertEqual(self.cst3.term_resolved, self.cst1.term_resolved)
@ -108,12 +94,10 @@ class TestConstituentaAPI(APITestCase):
self.assertEqual(self.cst3.definition_resolved, f'{self.cst1.term_resolved} form1') self.assertEqual(self.cst3.definition_resolved, f'{self.cst1.term_resolved} form1')
self.assertEqual(response.data['definition_resolved'], f'{self.cst1.term_resolved} form1') self.assertEqual(response.data['definition_resolved'], f'{self.cst1.term_resolved} form1')
@decl_endpoint('/api/constituents/{item}', method='patch')
def test_readonly_cst_fields(self): def test_readonly_cst_fields(self):
data = {'alias': 'X33', 'order': 10} data = {'alias': 'X33', 'order': 10}
response = self.client.patch( response = self.execute(data, item=self.cst1.id)
f'/api/constituents/{self.cst1.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['alias'], 'X1') self.assertEqual(response.data['alias'], 'X1')
self.assertEqual(response.data['alias'], self.cst1.alias) self.assertEqual(response.data['alias'], self.cst1.alias)

View File

@ -1,26 +1,25 @@
''' Testing API: Library. ''' ''' Testing API: Library. '''
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status from rest_framework import status
from apps.users.models import User from apps.users.models import User
from apps.rsform.models import LibraryItem, LibraryItemType, Subscription, LibraryTemplate from apps.rsform.models import LibraryItem, LibraryItemType, Subscription, LibraryTemplate, RSForm
from ..utils import response_contains from ..utils import response_contains
from .EndpointTester import decl_endpoint, EndpointTester
class TestLibraryViewset(APITestCase):
class TestLibraryViewset(EndpointTester):
''' Testing Library view. ''' ''' Testing Library view. '''
def setUp(self): def setUp(self):
self.factory = APIRequestFactory() super().setUp()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.owned = LibraryItem.objects.create( self.owned = LibraryItem.objects.create(
item_type=LibraryItemType.RSFORM, item_type=LibraryItemType.RSFORM,
title='Test', title='Test',
alias='T1', alias='T1',
owner=self.user owner=self.user
) )
self.schema = RSForm(self.owned)
self.unowned = LibraryItem.objects.create( self.unowned = LibraryItem.objects.create(
item_type=LibraryItemType.RSFORM, item_type=LibraryItemType.RSFORM,
title='Test2', title='Test2',
@ -33,93 +32,79 @@ class TestLibraryViewset(APITestCase):
is_common=True is_common=True
) )
def test_create_anonymous(self): @decl_endpoint('/api/library', method='post')
self.client.logout() def test_create(self):
data = {'title': 'Title'} data = {'title': 'Title'}
response = self.client.post('/api/library', data=data, format='json') response = self.post(data=data)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_create_populate_user(self):
data = {'title': 'Title'}
response = self.client.post('/api/library', data=data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['title'], 'Title') self.assertEqual(response.data['title'], 'Title')
self.assertEqual(response.data['owner'], self.user.id) self.assertEqual(response.data['owner'], self.user.id)
self.logout()
data = {'title': 'Title2'}
self.assertForbidden(data)
@decl_endpoint('/api/library/{item}', method='patch')
def test_update(self): def test_update(self):
data = {'id': self.unowned.id, 'title': 'New title'}
self.assertForbidden(data, item=self.unowned.id)
data = {'id': self.owned.id, 'title': 'New title'} data = {'id': self.owned.id, 'title': 'New title'}
response = self.client.patch( response = self.execute(data, item=self.owned.id)
f'/api/library/{self.owned.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['title'], 'New title') self.assertEqual(response.data['title'], 'New title')
self.assertEqual(response.data['alias'], self.owned.alias) self.assertEqual(response.data['alias'], self.owned.alias)
def test_update_unowned(self): @decl_endpoint('/api/library/{item}', method='delete')
data = {'id': self.unowned.id, 'title': 'New title'}
response = self.client.patch(
f'/api/library/{self.unowned.id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_destroy(self): def test_destroy(self):
response = self.client.delete(f'/api/library/{self.owned.id}') response = self.execute(item=self.owned.id)
self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT]) self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT])
def test_destroy_admin_override(self): self.assertForbidden(item=self.unowned.id)
response = self.client.delete(f'/api/library/{self.unowned.id}') self.toggle_staff(True)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) response = self.execute(item=self.unowned.id)
self.user.is_staff = True
self.user.save()
response = self.client.delete(f'/api/library/{self.unowned.id}')
self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT]) self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT])
@decl_endpoint('/api/library/{item}/claim', method='post')
def test_claim(self): def test_claim(self):
response = self.client.post(f'/api/library/{self.owned.id}/claim') self.assertForbidden(item=self.owned.id)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.owned.is_common = True self.owned.is_common = True
self.owned.save() self.owned.save()
response = self.client.post(f'/api/library/{self.owned.id}/claim') self.assertNotModified(item=self.owned.id)
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED) self.assertForbidden(item=self.unowned.id)
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertFalse(self.user in self.unowned.subscribers()) self.assertFalse(self.user in self.unowned.subscribers())
self.unowned.is_common = True self.unowned.is_common = True
self.unowned.save() self.unowned.save()
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertOK(item=self.unowned.id)
self.unowned.refresh_from_db() self.unowned.refresh_from_db()
self.assertEqual(self.unowned.owner, self.user) self.assertEqual(self.unowned.owner, self.user)
self.assertEqual(self.unowned.owner, self.user) self.assertEqual(self.unowned.owner, self.user)
self.assertTrue(self.user in self.unowned.subscribers()) self.assertTrue(self.user in self.unowned.subscribers())
def test_claim_anonymous(self): self.logout()
self.client.logout() self.assertForbidden(item=self.owned.id)
response = self.client.post(f'/api/library/{self.owned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@decl_endpoint('/api/library/active', method='get')
def test_retrieve_common(self): def test_retrieve_common(self):
self.client.logout() response = self.execute()
response = self.client.get('/api/library/active')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, self.common))
self.assertFalse(response_contains(response, self.unowned))
self.assertFalse(response_contains(response, self.owned))
def test_retrieve_owned(self):
response = self.client.get('/api/library/active')
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, self.common)) self.assertTrue(response_contains(response, self.common))
self.assertFalse(response_contains(response, self.unowned)) self.assertFalse(response_contains(response, self.unowned))
self.assertTrue(response_contains(response, self.owned)) self.assertTrue(response_contains(response, self.owned))
self.logout()
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, self.common))
self.assertFalse(response_contains(response, self.unowned))
self.assertFalse(response_contains(response, self.owned))
@decl_endpoint('/api/library/active', method='get')
def test_retrieve_subscribed(self): def test_retrieve_subscribed(self):
response = self.client.get('/api/library/active') response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response_contains(response, self.unowned)) self.assertFalse(response_contains(response, self.unowned))
@ -127,21 +112,23 @@ class TestLibraryViewset(APITestCase):
Subscription.subscribe(user=self.user, item=self.unowned) Subscription.subscribe(user=self.user, item=self.unowned)
Subscription.subscribe(user=user2, item=self.unowned) Subscription.subscribe(user=user2, item=self.unowned)
Subscription.subscribe(user=user2, item=self.owned) Subscription.subscribe(user=user2, item=self.owned)
response = self.client.get('/api/library/active')
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, self.unowned)) self.assertTrue(response_contains(response, self.unowned))
self.assertEqual(len(response.data), 3) self.assertEqual(len(response.data), 3)
@decl_endpoint('/api/library/{item}/subscribe', method='post')
def test_subscriptions(self): def test_subscriptions(self):
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe') response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(self.user in self.unowned.subscribers()) self.assertFalse(self.user in self.unowned.subscribers())
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe') response = self.execute(item=self.unowned.id)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertTrue(self.user in self.unowned.subscribers()) self.assertTrue(self.user in self.unowned.subscribers())
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe') response = self.execute(item=self.unowned.id)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertTrue(self.user in self.unowned.subscribers()) self.assertTrue(self.user in self.unowned.subscribers())
@ -149,16 +136,40 @@ class TestLibraryViewset(APITestCase):
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(self.user in self.unowned.subscribers()) self.assertFalse(self.user in self.unowned.subscribers())
@decl_endpoint('/api/library/templates', method='get')
def test_retrieve_templates(self): def test_retrieve_templates(self):
response = self.client.get('/api/library/templates') response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response_contains(response, self.common)) self.assertFalse(response_contains(response, self.common))
self.assertFalse(response_contains(response, self.unowned)) self.assertFalse(response_contains(response, self.unowned))
self.assertFalse(response_contains(response, self.owned)) self.assertFalse(response_contains(response, self.owned))
LibraryTemplate.objects.create(lib_source=self.unowned) LibraryTemplate.objects.create(lib_source=self.unowned)
response = self.client.get('/api/library/templates') response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response_contains(response, self.common)) self.assertFalse(response_contains(response, self.common))
self.assertTrue(response_contains(response, self.unowned)) self.assertTrue(response_contains(response, self.unowned))
self.assertFalse(response_contains(response, self.owned)) self.assertFalse(response_contains(response, self.owned))
@decl_endpoint('/api/library/{item}/clone', method='post')
def test_clone_rsform(self):
x12 = self.schema.insert_new(
alias='X12',
term_raw = 'человек',
term_resolved = 'человек'
)
d2 = self.schema.insert_new(
alias='D2',
term_raw = '@{X12|plur}',
term_resolved = 'люди'
)
data = {'title': 'Title1337'}
response = self.execute(data, item=self.owned.id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['title'], data['title'])
self.assertEqual(response.data['items'][0]['alias'], x12.alias)
self.assertEqual(response.data['items'][0]['term_raw'], x12.term_raw)
self.assertEqual(response.data['items'][0]['term_resolved'], x12.term_resolved)
self.assertEqual(response.data['items'][1]['term_raw'], d2.term_raw)
self.assertEqual(response.data['items'][1]['term_resolved'], d2.term_resolved)

View File

@ -2,10 +2,8 @@
import os import os
import io import io
from zipfile import ZipFile from zipfile import ZipFile
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status from rest_framework import status
from apps.users.models import User
from apps.rsform.models import ( from apps.rsform.models import (
RSForm, RSForm,
Constituenta, Constituenta,
@ -17,44 +15,69 @@ from apps.rsform.models import (
from cctext import ReferenceType from cctext import ReferenceType
from ..utils import response_contains from ..utils import response_contains
from .EndpointTester import decl_endpoint, EndpointTester
class TestRSFormViewset(APITestCase):
class TestRSFormViewset(EndpointTester):
''' Testing RSForm view. ''' ''' Testing RSForm view. '''
def setUp(self): def setUp(self):
self.factory = APIRequestFactory() super().setUp()
self.user = User.objects.create(username='UserTest') self.schema = RSForm.create(title='Test', alias='T1', owner=self.user)
self.client = APIClient() self.schema_id = self.schema.item.id
self.client.force_authenticate(user=self.user)
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user)
self.unowned = RSForm.create(title='Test2', alias='T2') self.unowned = RSForm.create(title='Test2', alias='T2')
self.unowned_id = self.unowned.item.id
@decl_endpoint('/api/rsforms/create-detailed', method='post')
def test_create_rsform_file(self):
work_dir = os.path.dirname(os.path.abspath(__file__))
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
data = {'file': file, 'title': 'Test123', 'comment': '123', 'alias': 'ks1'}
response = self.client.post(self.endpoint, data=data, format='multipart')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['owner'], self.user.pk)
self.assertEqual(response.data['title'], 'Test123')
self.assertEqual(response.data['alias'], 'ks1')
self.assertEqual(response.data['comment'], '123')
@decl_endpoint('/api/rsforms/create-detailed', method='post')
def test_create_rsform_json(self):
data = {'title': 'Test123', 'comment': '123', 'alias': 'ks1'}
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['owner'], self.user.pk)
self.assertEqual(response.data['title'], 'Test123')
self.assertEqual(response.data['alias'], 'ks1')
self.assertEqual(response.data['comment'], '123')
@decl_endpoint('/api/rsforms', method='get')
def test_list(self): def test_list(self):
non_schema = LibraryItem.objects.create( non_schema = LibraryItem.objects.create(
item_type=LibraryItemType.OPERATIONS_SCHEMA, item_type=LibraryItemType.OPERATIONS_SCHEMA,
title='Test3' title='Test3'
) )
response = self.client.get('/api/rsforms') response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response_contains(response, non_schema)) self.assertFalse(response_contains(response, non_schema))
self.assertTrue(response_contains(response, self.unowned.item)) self.assertTrue(response_contains(response, self.unowned.item))
self.assertTrue(response_contains(response, self.owned.item)) self.assertTrue(response_contains(response, self.schema.item))
response = self.client.get('/api/library') response = self.client.get('/api/library')
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, non_schema)) self.assertTrue(response_contains(response, non_schema))
self.assertTrue(response_contains(response, self.unowned.item)) self.assertTrue(response_contains(response, self.unowned.item))
self.assertTrue(response_contains(response, self.owned.item)) self.assertTrue(response_contains(response, self.schema.item))
@decl_endpoint('/api/rsforms/{item}/contents', method='get')
def test_contents(self): def test_contents(self):
schema = RSForm.create(title='Title1') schema = RSForm.create(title='Title1')
schema.insert_new(alias='X1', insert_type=CstType.BASE) schema.insert_new('X1')
response = self.client.get(f'/api/rsforms/{schema.item.id}/contents') self.assertOK(item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
@decl_endpoint('/api/rsforms/{item}/details', method='get')
def test_details(self): def test_details(self):
schema = RSForm.create(title='Test', owner=self.user) schema = RSForm.create(title='Test', owner=self.user)
x1 = schema.insert_new('X1', CstType.BASE, 1) x1 = schema.insert_new('X1')
x2 = schema.insert_new('X2', CstType.BASE, 2) x2 = schema.insert_new('X2')
x1.term_raw = 'человек' x1.term_raw = 'человек'
x1.term_resolved = 'человек' x1.term_resolved = 'человек'
x2.term_raw = '@{X1|plur}' x2.term_raw = '@{X1|plur}'
@ -62,8 +85,7 @@ class TestRSFormViewset(APITestCase):
x1.save() x1.save()
x2.save() x2.save()
response = self.client.get(f'/api/rsforms/{schema.item.id}/details') response = self.execute(item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['title'], 'Test') self.assertEqual(response.data['title'], 'Test')
self.assertEqual(len(response.data['items']), 2) self.assertEqual(len(response.data['items']), 2)
@ -76,14 +98,12 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(response.data['items'][1]['term_resolved'], x2.term_resolved) self.assertEqual(response.data['items'][1]['term_resolved'], x2.term_resolved)
self.assertEqual(response.data['subscribers'], [self.user.pk]) self.assertEqual(response.data['subscribers'], [self.user.pk])
@decl_endpoint('/api/rsforms/{item}/check', method='post')
def test_check(self): def test_check(self):
schema = RSForm.create(title='Test') schema = RSForm.create(title='Test')
schema.insert_new('X1', CstType.BASE, 1) schema.insert_new('X1')
data = {'expression': 'X1=X1'} data = {'expression': 'X1=X1'}
response = self.client.post( response = self.execute(data, item=schema.item.id)
f'/api/rsforms/{schema.item.id}/check',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['parseResult'], True) self.assertEqual(response.data['parseResult'], True)
self.assertEqual(response.data['syntax'], 'math') self.assertEqual(response.data['syntax'], 'math')
@ -91,22 +111,17 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(response.data['typification'], 'LOGIC') self.assertEqual(response.data['typification'], 'LOGIC')
self.assertEqual(response.data['valueClass'], 'value') self.assertEqual(response.data['valueClass'], 'value')
response = self.client.post( self.assertOK(data, item=self.unowned_id)
f'/api/rsforms/{self.unowned.item.id}/check',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
def test_resolve(self): def test_resolve(self):
schema = RSForm.create(title='Test') schema = RSForm.create(title='Test')
x1 = schema.insert_new('X1', CstType.BASE, 1) x1 = schema.insert_new('X1')
x1.term_resolved = 'синий слон' x1.term_resolved = 'синий слон'
x1.save() x1.save()
data = {'text': '@{1|редкий} @{X1|plur,datv}'} data = {'text': '@{1|редкий} @{X1|plur,datv}'}
response = self.client.post( response = self.execute(data, item=schema.item.id)
f'/api/rsforms/{schema.item.id}/resolve',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['input'], '@{1|редкий} @{X1|plur,datv}') self.assertEqual(response.data['input'], '@{1|редкий} @{X1|plur,datv}')
self.assertEqual(response.data['output'], 'редким синим слонам') self.assertEqual(response.data['output'], 'редким синим слонам')
@ -128,19 +143,21 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(response.data['refs'][1]['pos_output']['start'], 7) self.assertEqual(response.data['refs'][1]['pos_output']['start'], 7)
self.assertEqual(response.data['refs'][1]['pos_output']['finish'], 19) self.assertEqual(response.data['refs'][1]['pos_output']['finish'], 19)
@decl_endpoint('/api/rsforms/import-trs', method='post')
def test_import_trs(self): def test_import_trs(self):
work_dir = os.path.dirname(os.path.abspath(__file__)) work_dir = os.path.dirname(os.path.abspath(__file__))
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file: with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
data = {'file': file} data = {'file': file}
response = self.client.post('/api/rsforms/import-trs', data=data, format='multipart') response = self.client.post(self.endpoint, data=data, format='multipart')
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['owner'], self.user.pk) self.assertEqual(response.data['owner'], self.user.pk)
self.assertTrue(response.data['title'] != '') self.assertTrue(response.data['title'] != '')
@decl_endpoint('/api/rsforms/{item}/export-trs', method='get')
def test_export_trs(self): def test_export_trs(self):
schema = RSForm.create(title='Test') schema = RSForm.create(title='Test')
schema.insert_new('X1', CstType.BASE, 1) schema.insert_new('X1')
response = self.client.get(f'/api/rsforms/{schema.item.id}/export-trs') response = self.execute(item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename=Schema.trs') self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename=Schema.trs')
with io.BytesIO(response.content) as stream: with io.BytesIO(response.content) as stream:
@ -148,31 +165,15 @@ class TestRSFormViewset(APITestCase):
self.assertIsNone(zipped_file.testzip()) self.assertIsNone(zipped_file.testzip())
self.assertIn('document.json', zipped_file.namelist()) self.assertIn('document.json', zipped_file.namelist())
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
def test_create_constituenta(self): def test_create_constituenta(self):
data = {'alias': 'X3', 'cst_type': 'basic'} data = {'alias': 'X3', 'cst_type': CstType.BASE}
response = self.client.post( self.assertForbidden(data, item=self.unowned_id)
f'/api/rsforms/{self.unowned.item.id}/cst-create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
item = self.owned.item self.schema.insert_new('X1')
Constituenta.objects.create( x2 = self.schema.insert_new('X2')
schema=item,
alias='X1', response = self.execute(data, item=self.schema_id)
cst_type='basic',
order=1
)
x2 = Constituenta.objects.create(
schema=item,
alias='X2',
cst_type='basic',
order=2
)
response = self.client.post(
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['new_cst']['alias'], 'X3') self.assertEqual(response.data['new_cst']['alias'], 'X3')
x3 = Constituenta.objects.get(alias=response.data['new_cst']['alias']) x3 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
@ -180,15 +181,12 @@ class TestRSFormViewset(APITestCase):
data = { data = {
'alias': 'X4', 'alias': 'X4',
'cst_type': 'basic', 'cst_type': CstType.BASE,
'insert_after': x2.id, 'insert_after': x2.id,
'term_raw': 'test', 'term_raw': 'test',
'term_forms': [{'text':'form1', 'tags':'sing,datv'}] 'term_forms': [{'text':'form1', 'tags':'sing,datv'}]
} }
response = self.client.post( response = self.execute(data, item=self.schema_id)
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['new_cst']['alias'], data['alias']) self.assertEqual(response.data['new_cst']['alias'], data['alias'])
x4 = Constituenta.objects.get(alias=response.data['new_cst']['alias']) x4 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
@ -196,144 +194,87 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(x4.term_raw, data['term_raw']) self.assertEqual(x4.term_raw, data['term_raw'])
self.assertEqual(x4.term_forms, data['term_forms']) self.assertEqual(x4.term_forms, data['term_forms'])
@decl_endpoint('/api/rsforms/{item}/cst-rename', method='patch')
def test_rename_constituenta(self): def test_rename_constituenta(self):
cst1 = Constituenta.objects.create( x1 = self.schema.insert_new(
alias='X1', alias='X1',
schema=self.owned.item,
order=1,
convention='Test', convention='Test',
term_raw='Test1', term_raw='Test1',
term_resolved='Test1', term_resolved='Test1',
term_forms=[{'text':'form1', 'tags':'sing,datv'}] term_forms=[{'text':'form1', 'tags':'sing,datv'}]
) )
cst2 = Constituenta.objects.create( x2_2 = self.unowned.insert_new('X2')
alias='X2', x3 = self.schema.insert_new(
schema=self.unowned.item,
order=1
)
cst3 = Constituenta.objects.create(
alias='X3', alias='X3',
schema=self.owned.item, order=2,
term_raw='Test3', term_raw='Test3',
term_resolved='Test3', term_resolved='Test3',
definition_raw='Test1', definition_raw='Test1',
definition_resolved='Test2' definition_resolved='Test2'
) )
data = {'target': cst2.pk, 'alias': 'D2', 'cst_type': 'term'} data = {'target': x2_2.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
response = self.client.patch( self.assertForbidden(data, item=self.unowned_id)
f'/api/rsforms/{self.unowned.item.id}/cst-rename', self.assertBadData(data, item=self.schema_id)
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.patch( data = {'target': x1.pk, 'alias': x1.alias, 'cst_type': CstType.TERM}
f'/api/rsforms/{self.owned.item.id}/cst-rename', self.assertBadData(data, item=self.schema_id)
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'target': cst1.pk, 'alias': cst1.alias, 'cst_type': 'term'} data = {'target': x1.pk, 'alias': x3.alias}
response = self.client.patch( self.assertBadData(data, item=self.schema_id)
f'/api/rsforms/{self.owned.item.id}/cst-rename',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'target': cst1.pk, 'alias': cst3.alias} d1 = self.schema.insert_new(
response = self.client.patch( alias='D1',
f'/api/rsforms/{self.owned.item.id}/cst-rename', term_raw = '@{X1|plur}',
data=data, format='json' definition_formal = 'X1'
) )
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(x1.order, 1)
self.assertEqual(x1.alias, 'X1')
self.assertEqual(x1.cst_type, CstType.BASE)
data = {'target': cst1.pk, 'alias': 'D2', 'cst_type': 'term'} data = {'target': x1.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
item = self.owned.item response = self.execute(data, item=self.schema_id)
d1 = Constituenta.objects.create(schema=item, alias='D1', cst_type='term', order=4)
d1.term_raw = '@{X1|plur}'
d1.definition_formal = 'X1'
d1.save()
self.assertEqual(d1.order, 4)
self.assertEqual(cst1.order, 1)
self.assertEqual(cst1.alias, 'X1')
self.assertEqual(cst1.cst_type, CstType.BASE)
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-rename',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['new_cst']['alias'], 'D2') self.assertEqual(response.data['new_cst']['alias'], 'D2')
self.assertEqual(response.data['new_cst']['cst_type'], 'term') self.assertEqual(response.data['new_cst']['cst_type'], CstType.TERM)
d1.refresh_from_db() d1.refresh_from_db()
cst1.refresh_from_db() x1.refresh_from_db()
self.assertEqual(d1.order, 4)
self.assertEqual(d1.term_resolved, '') self.assertEqual(d1.term_resolved, '')
self.assertEqual(d1.term_raw, '@{D2|plur}') self.assertEqual(d1.term_raw, '@{D2|plur}')
self.assertEqual(cst1.order, 1) self.assertEqual(x1.order, 1)
self.assertEqual(cst1.alias, 'D2') self.assertEqual(x1.alias, 'D2')
self.assertEqual(cst1.cst_type, CstType.TERM) self.assertEqual(x1.cst_type, CstType.TERM)
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
def test_substitute_constituenta(self): def test_substitute_constituenta(self):
x1 = Constituenta.objects.create( x1 = self.schema.insert_new(
alias='X1', alias='X1',
schema=self.owned.item,
order=1,
term_raw='Test1', term_raw='Test1',
term_resolved='Test1', term_resolved='Test1',
term_forms=[{'text':'form1', 'tags':'sing,datv'}] term_forms=[{'text':'form1', 'tags':'sing,datv'}]
) )
x2 = Constituenta.objects.create( x2 = self.schema.insert_new(
alias='X2', alias='X2',
schema=self.owned.item,
order=2,
term_raw='Test2' term_raw='Test2'
) )
unowned = Constituenta.objects.create( unowned = self.unowned.insert_new('X2')
alias='X2',
schema=self.unowned.item,
order=1
)
data = {'original': x1.pk, 'substitution': unowned.pk, 'transfer_term': True} data = {'original': x1.pk, 'substitution': unowned.pk, 'transfer_term': True}
response = self.client.patch( self.assertForbidden(data, item=self.unowned_id)
f'/api/rsforms/{self.unowned.item.id}/cst-substitute', self.assertBadData(data, item=self.schema_id)
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.patch(
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True} data = {'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}
response = self.client.patch( self.assertBadData(data, item=self.schema_id)
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True} data = {'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}
response = self.client.patch( self.assertBadData(data, item=self.schema_id)
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
d1 = Constituenta.objects.create( d1 = self.schema.insert_new(
alias='D1', alias='D1',
schema=self.owned.item,
order=3,
term_raw='@{X2|sing,datv}', term_raw='@{X2|sing,datv}',
definition_formal='X1' definition_formal='X1'
) )
data = {'original': x1.pk, 'substitution': x2.pk, 'transfer_term': True} data = {'original': x1.pk, 'substitution': x2.pk, 'transfer_term': True}
response = self.client.patch( response = self.execute(data, item=self.schema_id)
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
d1.refresh_from_db() d1.refresh_from_db()
@ -342,23 +283,20 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(d1.term_resolved, 'form1') self.assertEqual(d1.term_resolved, 'form1')
self.assertEqual(d1.definition_formal, 'X2') self.assertEqual(d1.definition_formal, 'X2')
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
def test_create_constituenta_data(self): def test_create_constituenta_data(self):
data = { data = {
'alias': 'X3', 'alias': 'X3',
'cst_type': 'basic', 'cst_type': CstType.BASE,
'convention': '1', 'convention': '1',
'term_raw': '2', 'term_raw': '2',
'definition_formal': '3', 'definition_formal': '3',
'definition_raw': '4' 'definition_raw': '4'
} }
item = self.owned.item response = self.execute(data, item=self.schema_id)
response = self.client.post(
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['new_cst']['alias'], 'X3') self.assertEqual(response.data['new_cst']['alias'], 'X3')
self.assertEqual(response.data['new_cst']['cst_type'], 'basic') self.assertEqual(response.data['new_cst']['cst_type'], CstType.BASE)
self.assertEqual(response.data['new_cst']['convention'], '1') self.assertEqual(response.data['new_cst']['convention'], '1')
self.assertEqual(response.data['new_cst']['term_raw'], '2') self.assertEqual(response.data['new_cst']['term_raw'], '2')
self.assertEqual(response.data['new_cst']['term_resolved'], '2') self.assertEqual(response.data['new_cst']['term_resolved'], '2')
@ -366,79 +304,66 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(response.data['new_cst']['definition_raw'], '4') self.assertEqual(response.data['new_cst']['definition_raw'], '4')
self.assertEqual(response.data['new_cst']['definition_resolved'], '4') self.assertEqual(response.data['new_cst']['definition_resolved'], '4')
@decl_endpoint('/api/rsforms/{item}/cst-delete-multiple', method='patch')
def test_delete_constituenta(self): def test_delete_constituenta(self):
schema = self.owned self.set_params(item=self.schema_id)
data = {'items': [1337]}
response = self.client.patch( data = {'items': [1337]}
f'/api/rsforms/{schema.item.id}/cst-delete-multiple', self.assertBadData(data)
data=data, format='json'
) x1 = self.schema.insert_new('X1')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) x2 = self.schema.insert_new('X2')
x1 = Constituenta.objects.create(schema=schema.item, alias='X1', cst_type='basic', order=1)
x2 = Constituenta.objects.create(schema=schema.item, alias='X2', cst_type='basic', order=2)
data = {'items': [x1.id]} data = {'items': [x1.id]}
response = self.client.patch( response = self.execute(data)
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
data=data, format='json'
)
x2.refresh_from_db() x2.refresh_from_db()
schema.item.refresh_from_db() self.schema.item.refresh_from_db()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['items']), 1) self.assertEqual(len(response.data['items']), 1)
self.assertEqual(schema.constituents().count(), 1) self.assertEqual(self.schema.constituents().count(), 1)
self.assertEqual(x2.alias, 'X2') self.assertEqual(x2.alias, 'X2')
self.assertEqual(x2.order, 1) self.assertEqual(x2.order, 1)
x3 = Constituenta.objects.create(schema=self.unowned.item, alias='X1', cst_type='basic', order=1) x3 = self.unowned.insert_new('X1')
data = {'items': [x3.id]} data = {'items': [x3.id]}
response = self.client.patch( self.assertBadData(data, item=self.schema_id)
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
def test_move_constituenta(self): def test_move_constituenta(self):
item = self.owned.item self.set_params(item=self.schema_id)
data = {'items': [1337], 'move_to': 1}
response = self.client.patch( data = {'items': [1337], 'move_to': 1}
f'/api/rsforms/{item.id}/cst-moveto', self.assertBadData(data)
data=data, format='json'
) x1 = self.schema.insert_new('X1')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) x2 = self.schema.insert_new('X2')
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=1)
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=2)
data = {'items': [x2.id], 'move_to': 1} data = {'items': [x2.id], 'move_to': 1}
response = self.client.patch( response = self.execute(data)
f'/api/rsforms/{item.id}/cst-moveto',
data=data, format='json'
)
x1.refresh_from_db() x1.refresh_from_db()
x2.refresh_from_db() x2.refresh_from_db()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], item.id) self.assertEqual(response.data['id'], self.schema_id)
self.assertEqual(x1.order, 2) self.assertEqual(x1.order, 2)
self.assertEqual(x2.order, 1) self.assertEqual(x2.order, 1)
x3 = Constituenta.objects.create(schema=self.unowned.item, alias='X1', cst_type='basic', order=1) x3 = self.unowned.insert_new('X1')
data = {'items': [x3.id], 'move_to': 1} data = {'items': [x3.id], 'move_to': 1}
response = self.client.patch( self.assertBadData(data)
f'/api/rsforms/{item.id}/cst-moveto',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
def test_reset_aliases(self): def test_reset_aliases(self):
item = self.owned.item self.set_params(item=self.schema_id)
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], item.id)
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=1) response = self.execute()
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=2) self.assertEqual(response.status_code, status.HTTP_200_OK)
d11 = Constituenta.objects.create(schema=item, alias='D11', cst_type='term', order=3) self.assertEqual(response.data['id'], self.schema_id)
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
x2 = self.schema.insert_new('X2')
x1 = self.schema.insert_new('X1')
d11 = self.schema.insert_new('D11')
response = self.execute()
x1.refresh_from_db() x1.refresh_from_db()
x2.refresh_from_db() x2.refresh_from_db()
d11.refresh_from_db() d11.refresh_from_db()
@ -450,103 +375,57 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(d11.order, 3) self.assertEqual(d11.order, 3)
self.assertEqual(d11.alias, 'D1') self.assertEqual(d11.alias, 'D1')
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases') self.assertOK()
self.assertEqual(response.status_code, status.HTTP_200_OK)
@decl_endpoint('/api/rsforms/{item}/load-trs', method='patch')
def test_load_trs(self): def test_load_trs(self):
schema = self.owned self.set_params(item=self.schema_id)
schema.item.title = 'Test11' self.schema.item.title = 'Test11'
schema.item.save() self.schema.item.save()
x1 = Constituenta.objects.create(schema=schema.item, alias='X1', cst_type='basic', order=1) x1 = self.schema.insert_new('X1')
work_dir = os.path.dirname(os.path.abspath(__file__)) work_dir = os.path.dirname(os.path.abspath(__file__))
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file: with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
data = {'file': file, 'load_metadata': False} data = {'file': file, 'load_metadata': False}
response = self.client.patch( response = self.client.patch(self.endpoint, data=data, format='multipart')
f'/api/rsforms/{schema.item.id}/load-trs', self.schema.item.refresh_from_db()
data=data, format='multipart'
)
schema.item.refresh_from_db()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(schema.item.title, 'Test11') self.assertEqual(self.schema.item.title, 'Test11')
self.assertEqual(len(response.data['items']), 25) self.assertEqual(len(response.data['items']), 25)
self.assertEqual(schema.constituents().count(), 25) self.assertEqual(self.schema.constituents().count(), 25)
self.assertFalse(Constituenta.objects.filter(pk=x1.id).exists()) self.assertFalse(Constituenta.objects.filter(pk=x1.id).exists())
def test_clone(self): @decl_endpoint('/api/rsforms/{item}/cst-produce-structure', method='patch')
item = self.owned.item
item.title = 'Test11'
item.save()
x1 = Constituenta.objects.create(schema=item, alias='X12', cst_type='basic', order=1)
d1 = Constituenta.objects.create(schema=item, alias='D2', cst_type='term', order=1)
x1.term_raw = 'человек'
x1.term_resolved = 'человек'
d1.term_raw = '@{X12|plur}'
d1.term_resolved = 'люди'
x1.save()
d1.save()
data = {'title': 'Title'}
response = self.client.post(
f'/api/library/{item.id}/clone',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['title'], 'Title')
self.assertEqual(response.data['items'][0]['alias'], x1.alias)
self.assertEqual(response.data['items'][0]['term_raw'], x1.term_raw)
self.assertEqual(response.data['items'][0]['term_resolved'], x1.term_resolved)
self.assertEqual(response.data['items'][1]['term_raw'], d1.term_raw)
self.assertEqual(response.data['items'][1]['term_resolved'], d1.term_resolved)
def test_produce_structure(self): def test_produce_structure(self):
item = self.owned.item self.set_params(item=self.schema_id)
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=1) x1 = self.schema.insert_new('X1')
s1 = Constituenta.objects.create(schema=item, alias='S1', cst_type='structure', order=2) s1 = self.schema.insert_new(
s2 = Constituenta.objects.create(schema=item, alias='S2', cst_type='structure', order=3) alias='S1',
s3 = Constituenta.objects.create(schema=item, alias='S3', cst_type='structure', order=4) definition_formal='(X1×X1)'
a1 = Constituenta.objects.create(schema=item, alias='A1', cst_type='axiom', order=5)
f1 = Constituenta.objects.create(schema=item, alias='F10', cst_type='function', order=6)
invalid_id = f1.id + 1
s1.definition_formal = '(X1×X1)' # (X1×X1)
s2.definition_formal = 'invalid'
s3.definition_formal = 'X1×(X1×(X1))×(X1×X1)'
a1.definition_formal = '1=1'
f1.definition_formal = '[α∈X1, β∈X1] Fi1[{α,β}](S1)'
s1.save()
s2.save()
s3.save()
a1.save()
f1.save()
data = {'target': invalid_id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
) )
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) s2 = self.schema.insert_new(
alias='S2',
data = {'target': x1.id} definition_formal='invalid'
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
) )
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) s3 = self.schema.insert_new(
alias='S3',
data = {'target': s2.id} definition_formal='X1×(X1×(X1))×(X1×X1)'
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
) )
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) a1 = self.schema.insert_new(
alias='A1',
# Testing simple structure definition_formal='1=1'
s1.refresh_from_db()
data = {'target': s1.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
) )
f1 = self.schema.insert_new(
alias='F10',
definition_formal='[α∈X1, β∈X1] Fi1[{α,β}](S1)'
)
invalid_id = f1.pk + 1337
self.assertBadData({'target': invalid_id})
self.assertBadData({'target': x1.id})
self.assertBadData({'target': s2.id})
# Testing simple structure
response = self.execute({'target': s1.id})
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema'] result = response.data['schema']
items = [item for item in result['items'] if item['id'] in response.data['cst_list']] items = [item for item in result['items'] if item['id'] in response.data['cst_list']]
@ -558,11 +437,7 @@ class TestRSFormViewset(APITestCase):
# Testing complex structure # Testing complex structure
s3.refresh_from_db() s3.refresh_from_db()
data = {'target': s3.id} response = self.execute({'target': s3.id})
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema'] result = response.data['schema']
items = [item for item in result['items'] if item['id'] in response.data['cst_list']] items = [item for item in result['items'] if item['id'] in response.data['cst_list']]
@ -572,11 +447,7 @@ class TestRSFormViewset(APITestCase):
# Testing function # Testing function
f1.refresh_from_db() f1.refresh_from_db()
data = {'target': f1.id} response = self.execute({'target': f1.id})
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema'] result = response.data['schema']
items = [item for item in result['items'] if item['id'] in response.data['cst_list']] items = [item for item in result['items'] if item['id'] in response.data['cst_list']]

View File

@ -1,109 +1,41 @@
''' Testing views ''' ''' Testing views '''
import os
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework.exceptions import ErrorDetail from rest_framework.exceptions import ErrorDetail
from rest_framework import status from rest_framework import status
from apps.users.models import User from .EndpointTester import decl_endpoint, EndpointTester
from apps.rsform.models import RSForm
from apps.rsform.views import (
convert_to_ascii,
convert_to_math,
parse_expression
)
class TestRSLanguageViews(APITestCase): class TestRSLanguageViews(EndpointTester):
def setUp(self): ''' Test RS language endpoints. '''
self.factory = APIRequestFactory() @decl_endpoint('/api/rslang/to-ascii', method='post')
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_create_rsform(self):
work_dir = os.path.dirname(os.path.abspath(__file__))
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
data = {'file': file, 'title': 'Test123', 'comment': '123', 'alias': 'ks1'}
response = self.client.post(
'/api/rsforms/create-detailed',
data=data, format='multipart'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['owner'], self.user.pk)
self.assertEqual(response.data['title'], 'Test123')
self.assertEqual(response.data['alias'], 'ks1')
self.assertEqual(response.data['comment'], '123')
def test_create_rsform_fallback(self):
data = {'title': 'Test123', 'comment': '123', 'alias': 'ks1'}
response = self.client.post(
'/api/rsforms/create-detailed',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['owner'], self.user.pk)
self.assertEqual(response.data['title'], 'Test123')
self.assertEqual(response.data['alias'], 'ks1')
self.assertEqual(response.data['comment'], '123')
def test_convert_to_ascii(self): def test_convert_to_ascii(self):
data = {'data': '1=1'}
self.assertBadData(data)
data = {'expression': '1=1'} data = {'expression': '1=1'}
request = self.factory.post( response = self.execute(data)
'/api/rslang/to-ascii',
data=data, format='json'
)
response = convert_to_ascii(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], r'1 \eq 1') self.assertEqual(response.data['result'], r'1 \eq 1')
def test_convert_to_ascii_missing_data(self): @decl_endpoint('/api/rslang/to-math', method='post')
data = {'data': '1=1'}
request = self.factory.post(
'/api/rslang/to-ascii',
data=data, format='json'
)
response = convert_to_ascii(request)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
def test_convert_to_math(self): def test_convert_to_math(self):
data = {'data': r'1 \eq 1'}
self.assertBadData(data)
data = {'expression': r'1 \eq 1'} data = {'expression': r'1 \eq 1'}
request = self.factory.post( response = self.execute(data)
'/api/rslang/to-math',
data=data, format='json'
)
response = convert_to_math(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], r'1=1') self.assertEqual(response.data['result'], r'1=1')
def test_convert_to_math_missing_data(self): @decl_endpoint('/api/rslang/parse-expression', method='post')
data = {'data': r'1 \eq 1'}
request = self.factory.post(
'/api/rslang/to-math',
data=data, format='json'
)
response = convert_to_math(request)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
def test_parse_expression(self): def test_parse_expression(self):
data = {'data': r'1=1'}
self.assertBadData(data)
data = {'expression': r'1=1'} data = {'expression': r'1=1'}
request = self.factory.post( response = self.execute(data)
'/api/rslang/parse-expression',
data=data, format='json'
)
response = parse_expression(request)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['parseResult'], True) self.assertEqual(response.data['parseResult'], True)
self.assertEqual(response.data['syntax'], 'math') self.assertEqual(response.data['syntax'], 'math')
self.assertEqual(response.data['astText'], '[=[1][1]]') self.assertEqual(response.data['astText'], '[=[1][1]]')
def test_parse_expression_missing_data(self):
data = {'data': r'1=1'}
request = self.factory.post(
'/api/rslang/parse-expression',
data=data, format='json'
)
response = parse_expression(request)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIsInstance(response.data['expression'][0], ErrorDetail)

View File

@ -1,185 +1,141 @@
''' Testing API: Versions. ''' ''' Testing API: Versions. '''
import io import io
from typing import cast
from sys import version
from zipfile import ZipFile from zipfile import ZipFile
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status from rest_framework import status
from apps.users.models import User
from apps.rsform.models import RSForm, Constituenta from apps.rsform.models import RSForm, Constituenta
from .EndpointTester import decl_endpoint, EndpointTester
class TestVersionViews(APITestCase):
class TestVersionViews(EndpointTester):
''' Testing versioning endpoints. ''' ''' Testing versioning endpoints. '''
def setUp(self): def setUp(self):
self.factory = APIRequestFactory() super().setUp()
self.user = User.objects.create(username='UserTest') self.owned = RSForm.create(title='Test', alias='T1', owner=self.user).item
self.client = APIClient() self.unowned = RSForm.create(title='Test2', alias='T2').item
self.client.force_authenticate(user=self.user)
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user)
self.unowned = RSForm.create(title='Test2', alias='T2')
self.x1 = Constituenta.objects.create( self.x1 = Constituenta.objects.create(
schema=self.owned.item, schema=self.owned,
alias='X1', alias='X1',
cst_type='basic', cst_type='basic',
convention='testStart', convention='testStart',
order=1 order=1
) )
@decl_endpoint('/api/rsforms/{schema}/versions/create', method='post')
def test_create_version(self): def test_create_version(self):
invalid_data = {'description': 'test'} invalid_data = {'description': 'test'}
data = {'version': '1.0.0', 'description': 'test'}
invalid_id = 1338 invalid_id = 1338
response = self.client.post( data = {'version': '1.0.0', 'description': 'test'}
f'/api/rsforms/{invalid_id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
response = self.client.post( self.assertNotFound(data, schema=invalid_id)
f'/api/rsforms/{self.unowned.item.id}/versions/create', self.assertForbidden(data, schema=self.unowned.id)
data=data, format='json' self.assertBadData(invalid_data, schema=self.owned.id)
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.post( response = self.execute(data, schema=self.owned.id)
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=invalid_data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
response = self.client.post(
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue('version' in response.data) self.assertTrue('version' in response.data)
self.assertTrue('schema' in response.data) self.assertTrue('schema' in response.data)
self.assertTrue(response.data['version'] in [v['id'] for v in response.data['schema']['versions']]) self.assertTrue(response.data['version'] in [v['id'] for v in response.data['schema']['versions']])
@decl_endpoint('/api/rsforms/{schema}/versions/{version}', method='get')
def test_retrieve_version(self): def test_retrieve_version(self):
data = {'version': '1.0.0', 'description': 'test'} version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
response = self.client.post( invalid_id = version_id + 1337
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
version_id = response.data['version']
invalid_id = 1338 self.assertNotFound(schema=invalid_id, version=invalid_id)
response = self.client.get(f'/api/rsforms/{invalid_id}/versions/{invalid_id}') self.assertNotFound(schema=self.owned.id, version=invalid_id)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertNotFound(schema=invalid_id, version=version_id)
response = self.client.get(f'/api/rsforms/{self.owned.item.id}/versions/{invalid_id}') self.assertNotFound(schema=self.unowned.id, version=version_id)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
response = self.client.get(f'/api/rsforms/{invalid_id}/versions/{version_id}')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
response = self.client.get(f'/api/rsforms/{self.unowned.item.id}/versions/{version_id}')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.owned.item.alias = 'NewName' self.owned.alias = 'NewName'
self.owned.item.save() self.owned.save()
self.x1.alias = 'X33' self.x1.alias = 'X33'
self.x1.save() self.x1.save()
response = self.client.get(f'/api/rsforms/{self.owned.item.id}/versions/{version_id}') response = self.execute(schema=self.owned.id, version=version_id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertNotEqual(response.data['alias'], self.owned.item.alias) self.assertNotEqual(response.data['alias'], self.owned.alias)
self.assertNotEqual(response.data['items'][0]['alias'], self.x1.alias) self.assertNotEqual(response.data['items'][0]['alias'], self.x1.alias)
self.assertEqual(response.data['version'], version_id) self.assertEqual(response.data['version'], version_id)
@decl_endpoint('/api/versions/{version}', method='get')
def test_access_version(self): def test_access_version(self):
data = {'version': '1.0.0', 'description': 'test'} data = {'version': '1.0.0', 'description': 'test'}
response = self.client.post( version_id = self._create_version(data)
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
version_id = response.data['version']
invalid_id = version_id + 1337 invalid_id = version_id + 1337
response = self.client.get(f'/api/versions/{invalid_id}') self.assertNotFound(version=invalid_id)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.client.logout() self.set_params(version=version_id)
response = self.client.get(f'/api/versions/{version_id}') self.logout()
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['version'], data['version']) self.assertEqual(response.data['version'], data['version'])
self.assertEqual(response.data['description'], data['description']) self.assertEqual(response.data['description'], data['description'])
self.assertEqual(response.data['item'], self.owned.item.id) self.assertEqual(response.data['item'], self.owned.id)
response = self.client.patch( data = {'version': '1.2.0', 'description': 'test1'}
f'/api/versions/{version_id}', self.method = 'patch'
data=data, format='json' self.assertForbidden(data)
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.delete(f'/api/versions/{version_id}') self.method = 'delete'
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertForbidden()
self.client.force_authenticate(user=self.user) self.client.force_authenticate(user=self.user)
self.method = 'patch'
data = {'version': '1.1.0', 'description': 'test1'} self.assertOK(data)
response = self.client.patch( response = self.get()
f'/api/versions/{version_id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
response = self.client.get(f'/api/versions/{version_id}')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['version'], data['version']) self.assertEqual(response.data['version'], data['version'])
self.assertEqual(response.data['description'], data['description']) self.assertEqual(response.data['description'], data['description'])
response = self.client.delete(f'/api/versions/{version_id}') response = self.delete()
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
response = self.get()
response = self.client.get(f'/api/versions/{version_id}')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
@decl_endpoint('/api/rsforms/{schema}/versions/{version}', method='get')
def test_retrieve_version_details(self): def test_retrieve_version_details(self):
a1 = Constituenta.objects.create( a1 = Constituenta.objects.create(
schema=self.owned.item, schema=self.owned,
alias='A1', alias='A1',
cst_type='axiom', cst_type='axiom',
definition_formal='X1=X1', definition_formal='X1=X1',
order=2 order=2
) )
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
data = {'version': '1.0.0', 'description': 'test'}
response = self.client.post(
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=data, format='json'
)
version_id = response.data['version']
a1.definition_formal = 'X1=X2' a1.definition_formal = 'X1=X2'
a1.save() a1.save()
response = self.client.get(f'/api/rsforms/{self.owned.item.id}/versions/{version_id}') response = self.get(schema=self.owned.id, version=version_id)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
loaded_a1 = response.data['items'][1] loaded_a1 = response.data['items'][1]
self.assertEqual(loaded_a1['definition_formal'], 'X1=X1') self.assertEqual(loaded_a1['definition_formal'], 'X1=X1')
self.assertEqual(loaded_a1['parse']['status'], 'verified') self.assertEqual(loaded_a1['parse']['status'], 'verified')
@decl_endpoint('/api/versions/{version}/export-file', method='get')
def test_export_version(self): def test_export_version(self):
invalid_id = 1338 invalid_id = 1338
response = self.client.get(f'/api/versions/{invalid_id}/export-file') self.assertNotFound(version=invalid_id)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
data = {'version': '1.0.0', 'description': 'test'} version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
response = self.client.post( response = self.get(version=version_id)
f'/api/rsforms/{self.owned.item.id}/versions/create',
data=data, format='json'
)
version_id = response.data['version']
response = self.client.get(f'/api/versions/{version_id}/export-file')
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual( self.assertEqual(
response.headers['Content-Disposition'], response.headers['Content-Disposition'],
f'attachment; filename={self.owned.item.alias}.trs' f'attachment; filename={self.owned.alias}.trs'
) )
with io.BytesIO(response.content) as stream: with io.BytesIO(response.content) as stream:
with ZipFile(stream, 'r') as zipped_file: with ZipFile(stream, 'r') as zipped_file:
self.assertIsNone(zipped_file.testzip()) self.assertIsNone(zipped_file.testzip())
self.assertIn('document.json', zipped_file.namelist()) self.assertIn('document.json', zipped_file.namelist())
def _create_version(self, data) -> int:
response = self.client.post(
f'/api/rsforms/{self.owned.id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
return response.data['version'] # type: ignore

View File

@ -64,7 +64,7 @@ def write_zipped_json(json_data: dict, json_filename: str) -> bytes:
return content.getvalue() return content.getvalue()
def apply_pattern(text: str, mapping: dict[str, str], pattern: re.Pattern[str]) -> str: def apply_pattern(text: str, mapping: dict[str, str], pattern: re.Pattern[str]) -> str:
''' Apply mapping to matching in regular expression patter subgroup 1 ''' ''' Apply mapping to matching in regular expression pattern subgroup 1 '''
if text == '' or pattern == '': if text == '' or pattern == '':
return text return text
pos_input: int = 0 pos_input: int = 0