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. '''
from typing import Dict, Iterable, Optional, cast
from typing import Dict, Iterable, Optional, Union, cast
from django.db import transaction
from django.db.models import QuerySet
from django.core.exceptions import ValidationError
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 .Constituenta import CstType, Constituenta
from .Version import Version
@ -90,18 +90,27 @@ class RSForm:
return result
@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.
All following constituents order is shifted by 1 position. '''
if self.constituents().filter(alias=alias).exists():
raise ValidationError(msg.aliasTaken(alias))
position = self._get_insert_position(position)
if cst_type is None:
cst_type = guess_type(alias)
self._shift_positions(position, 1)
result = Constituenta.objects.create(
schema=self.item,
order=position,
alias=alias,
cst_type=insert_type
cst_type=cst_type,
**kwargs
)
self.item.save()
result.refresh_from_db()

View File

@ -1,6 +1,6 @@
''' Models: Definitions and utility function for RSLanguage. '''
import json
from typing import Tuple
from typing import Tuple, cast
from enum import IntEnum , unique
from django.db.models import TextChoices
@ -54,6 +54,14 @@ def get_type_prefix(cst_type: CstType) -> str:
return 'T'
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]:
''' Generate prefix and alias for structure generation. '''
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 '''
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 cctext import ReferenceType, split_grams
from cctext import split_grams
from apps.users.models import User
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
)
from .EndpointTester import decl_endpoint, EndpointTester
class TestNaturalLanguageViews(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.client = APIClient()
class TestNaturalLanguageViews(EndpointTester):
''' Test natural language endpoints. '''
def _assert_tags(self, actual: str, expected: str):
self.assertEqual(set(split_grams(actual)), set(split_grams(expected)))
@decl_endpoint(endpoint='/api/cctext/parse', method='post')
def test_parse_text(self):
data = {'text': 'синим слонам'}
request = self.factory.post(
'/api/cctext/parse',
data=data, format='json'
)
response = parse_text(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
@decl_endpoint(endpoint='/api/cctext/inflect', method='post')
def test_inflect(self):
data = {'text': 'синий слон', 'grams': 'plur,datv'}
request = self.factory.post(
'/api/cctext/inflect',
data=data, format='json'
)
response = inflect(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], 'синим слонам')
@decl_endpoint(endpoint='/api/cctext/generate-lexeme', method='post')
def test_generate_lexeme(self):
data = {'text': 'синий слон'}
request = self.factory.post(
'/api/cctext/generate-lexeme',
data=data, format='json'
)
response = generate_lexeme(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['items']), 12)
self.assertEqual(response.data['items'][0]['text'], 'синий слон')

View File

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

View File

@ -1,26 +1,25 @@
''' Testing API: Library. '''
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status
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 .EndpointTester import decl_endpoint, EndpointTester
class TestLibraryViewset(APITestCase):
class TestLibraryViewset(EndpointTester):
''' Testing Library view. '''
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
super().setUp()
self.owned = LibraryItem.objects.create(
item_type=LibraryItemType.RSFORM,
title='Test',
alias='T1',
owner=self.user
)
self.schema = RSForm(self.owned)
self.unowned = LibraryItem.objects.create(
item_type=LibraryItemType.RSFORM,
title='Test2',
@ -33,93 +32,79 @@ class TestLibraryViewset(APITestCase):
is_common=True
)
def test_create_anonymous(self):
self.client.logout()
@decl_endpoint('/api/library', method='post')
def test_create(self):
data = {'title': 'Title'}
response = self.client.post('/api/library', data=data, format='json')
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')
response = self.post(data=data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['title'], 'Title')
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):
data = {'id': self.unowned.id, 'title': 'New title'}
self.assertForbidden(data, item=self.unowned.id)
data = {'id': self.owned.id, 'title': 'New title'}
response = self.client.patch(
f'/api/library/{self.owned.id}',
data=data, format='json'
)
response = self.execute(data, item=self.owned.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['title'], 'New title')
self.assertEqual(response.data['alias'], self.owned.alias)
def test_update_unowned(self):
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)
@decl_endpoint('/api/library/{item}', method='delete')
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])
def test_destroy_admin_override(self):
response = self.client.delete(f'/api/library/{self.unowned.id}')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.user.is_staff = True
self.user.save()
response = self.client.delete(f'/api/library/{self.unowned.id}')
self.assertForbidden(item=self.unowned.id)
self.toggle_staff(True)
response = self.execute(item=self.unowned.id)
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):
response = self.client.post(f'/api/library/{self.owned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertForbidden(item=self.owned.id)
self.owned.is_common = True
self.owned.save()
response = self.client.post(f'/api/library/{self.owned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertNotModified(item=self.owned.id)
self.assertForbidden(item=self.unowned.id)
self.assertFalse(self.user in self.unowned.subscribers())
self.unowned.is_common = True
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.assertEqual(self.unowned.owner, self.user)
self.assertEqual(self.unowned.owner, self.user)
self.assertTrue(self.user in self.unowned.subscribers())
def test_claim_anonymous(self):
self.client.logout()
response = self.client.post(f'/api/library/{self.owned.id}/claim')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.logout()
self.assertForbidden(item=self.owned.id)
@decl_endpoint('/api/library/active', method='get')
def test_retrieve_common(self):
self.client.logout()
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')
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.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):
response = self.client.get('/api/library/active')
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK)
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=user2, item=self.unowned)
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.assertTrue(response_contains(response, self.unowned))
self.assertEqual(len(response.data), 3)
@decl_endpoint('/api/library/{item}/subscribe', method='post')
def test_subscriptions(self):
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
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.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.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.assertFalse(self.user in self.unowned.subscribers())
@decl_endpoint('/api/library/templates', method='get')
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.assertFalse(response_contains(response, self.common))
self.assertFalse(response_contains(response, self.unowned))
self.assertFalse(response_contains(response, self.owned))
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.assertFalse(response_contains(response, self.common))
self.assertTrue(response_contains(response, self.unowned))
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 io
from zipfile import ZipFile
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status
from apps.users.models import User
from apps.rsform.models import (
RSForm,
Constituenta,
@ -17,44 +15,69 @@ from apps.rsform.models import (
from cctext import ReferenceType
from ..utils import response_contains
from .EndpointTester import decl_endpoint, EndpointTester
class TestRSFormViewset(APITestCase):
class TestRSFormViewset(EndpointTester):
''' Testing RSForm view. '''
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user)
super().setUp()
self.schema = RSForm.create(title='Test', alias='T1', owner=self.user)
self.schema_id = self.schema.item.id
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):
non_schema = LibraryItem.objects.create(
item_type=LibraryItemType.OPERATIONS_SCHEMA,
title='Test3'
)
response = self.client.get('/api/rsforms')
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response_contains(response, non_schema))
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')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response_contains(response, non_schema))
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):
schema = RSForm.create(title='Title1')
schema.insert_new(alias='X1', insert_type=CstType.BASE)
response = self.client.get(f'/api/rsforms/{schema.item.id}/contents')
self.assertEqual(response.status_code, status.HTTP_200_OK)
schema.insert_new('X1')
self.assertOK(item=schema.item.id)
@decl_endpoint('/api/rsforms/{item}/details', method='get')
def test_details(self):
schema = RSForm.create(title='Test', owner=self.user)
x1 = schema.insert_new('X1', CstType.BASE, 1)
x2 = schema.insert_new('X2', CstType.BASE, 2)
x1 = schema.insert_new('X1')
x2 = schema.insert_new('X2')
x1.term_raw = 'человек'
x1.term_resolved = 'человек'
x2.term_raw = '@{X1|plur}'
@ -62,8 +85,7 @@ class TestRSFormViewset(APITestCase):
x1.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.data['title'], 'Test')
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['subscribers'], [self.user.pk])
@decl_endpoint('/api/rsforms/{item}/check', method='post')
def test_check(self):
schema = RSForm.create(title='Test')
schema.insert_new('X1', CstType.BASE, 1)
schema.insert_new('X1')
data = {'expression': 'X1=X1'}
response = self.client.post(
f'/api/rsforms/{schema.item.id}/check',
data=data, format='json'
)
response = self.execute(data, item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['parseResult'], True)
self.assertEqual(response.data['syntax'], 'math')
@ -91,22 +111,17 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(response.data['typification'], 'LOGIC')
self.assertEqual(response.data['valueClass'], 'value')
response = self.client.post(
f'/api/rsforms/{self.unowned.item.id}/check',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertOK(data, item=self.unowned_id)
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
def test_resolve(self):
schema = RSForm.create(title='Test')
x1 = schema.insert_new('X1', CstType.BASE, 1)
x1 = schema.insert_new('X1')
x1.term_resolved = 'синий слон'
x1.save()
data = {'text': '@{1|редкий} @{X1|plur,datv}'}
response = self.client.post(
f'/api/rsforms/{schema.item.id}/resolve',
data=data, format='json'
)
response = self.execute(data, item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['input'], '@{1|редкий} @{X1|plur,datv}')
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']['finish'], 19)
@decl_endpoint('/api/rsforms/import-trs', method='post')
def test_import_trs(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}
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.data['owner'], self.user.pk)
self.assertTrue(response.data['title'] != '')
@decl_endpoint('/api/rsforms/{item}/export-trs', method='get')
def test_export_trs(self):
schema = RSForm.create(title='Test')
schema.insert_new('X1', CstType.BASE, 1)
response = self.client.get(f'/api/rsforms/{schema.item.id}/export-trs')
schema.insert_new('X1')
response = self.execute(item=schema.item.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename=Schema.trs')
with io.BytesIO(response.content) as stream:
@ -148,31 +165,15 @@ class TestRSFormViewset(APITestCase):
self.assertIsNone(zipped_file.testzip())
self.assertIn('document.json', zipped_file.namelist())
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
def test_create_constituenta(self):
data = {'alias': 'X3', 'cst_type': 'basic'}
response = self.client.post(
f'/api/rsforms/{self.unowned.item.id}/cst-create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
data = {'alias': 'X3', 'cst_type': CstType.BASE}
self.assertForbidden(data, item=self.unowned_id)
item = self.owned.item
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
)
response = self.client.post(
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
self.schema.insert_new('X1')
x2 = self.schema.insert_new('X2')
response = self.execute(data, item=self.schema_id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['new_cst']['alias'], 'X3')
x3 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
@ -180,15 +181,12 @@ class TestRSFormViewset(APITestCase):
data = {
'alias': 'X4',
'cst_type': 'basic',
'cst_type': CstType.BASE,
'insert_after': x2.id,
'term_raw': 'test',
'term_forms': [{'text':'form1', 'tags':'sing,datv'}]
}
response = self.client.post(
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
response = self.execute(data, item=self.schema_id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['new_cst']['alias'], data['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_forms, data['term_forms'])
@decl_endpoint('/api/rsforms/{item}/cst-rename', method='patch')
def test_rename_constituenta(self):
cst1 = Constituenta.objects.create(
x1 = self.schema.insert_new(
alias='X1',
schema=self.owned.item,
order=1,
convention='Test',
term_raw='Test1',
term_resolved='Test1',
term_forms=[{'text':'form1', 'tags':'sing,datv'}]
)
cst2 = Constituenta.objects.create(
alias='X2',
schema=self.unowned.item,
order=1
)
cst3 = Constituenta.objects.create(
x2_2 = self.unowned.insert_new('X2')
x3 = self.schema.insert_new(
alias='X3',
schema=self.owned.item, order=2,
term_raw='Test3',
term_resolved='Test3',
definition_raw='Test1',
definition_resolved='Test2'
)
data = {'target': cst2.pk, 'alias': 'D2', 'cst_type': 'term'}
response = self.client.patch(
f'/api/rsforms/{self.unowned.item.id}/cst-rename',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
data = {'target': x2_2.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
self.assertForbidden(data, item=self.unowned_id)
self.assertBadData(data, item=self.schema_id)
response = self.client.patch(
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': x1.pk, 'alias': x1.alias, 'cst_type': CstType.TERM}
self.assertBadData(data, item=self.schema_id)
data = {'target': cst1.pk, 'alias': cst1.alias, 'cst_type': 'term'}
response = self.client.patch(
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': x1.pk, 'alias': x3.alias}
self.assertBadData(data, item=self.schema_id)
data = {'target': cst1.pk, 'alias': cst3.alias}
response = self.client.patch(
f'/api/rsforms/{self.owned.item.id}/cst-rename',
data=data, format='json'
d1 = self.schema.insert_new(
alias='D1',
term_raw = '@{X1|plur}',
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'}
item = self.owned.item
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'
)
data = {'target': x1.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
response = self.execute(data, item=self.schema_id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
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()
cst1.refresh_from_db()
self.assertEqual(d1.order, 4)
x1.refresh_from_db()
self.assertEqual(d1.term_resolved, '')
self.assertEqual(d1.term_raw, '@{D2|plur}')
self.assertEqual(cst1.order, 1)
self.assertEqual(cst1.alias, 'D2')
self.assertEqual(cst1.cst_type, CstType.TERM)
self.assertEqual(x1.order, 1)
self.assertEqual(x1.alias, 'D2')
self.assertEqual(x1.cst_type, CstType.TERM)
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
def test_substitute_constituenta(self):
x1 = Constituenta.objects.create(
x1 = self.schema.insert_new(
alias='X1',
schema=self.owned.item,
order=1,
term_raw='Test1',
term_resolved='Test1',
term_forms=[{'text':'form1', 'tags':'sing,datv'}]
)
x2 = Constituenta.objects.create(
x2 = self.schema.insert_new(
alias='X2',
schema=self.owned.item,
order=2,
term_raw='Test2'
)
unowned = Constituenta.objects.create(
alias='X2',
schema=self.unowned.item,
order=1
)
unowned = self.unowned.insert_new('X2')
data = {'original': x1.pk, 'substitution': unowned.pk, 'transfer_term': True}
response = self.client.patch(
f'/api/rsforms/{self.unowned.item.id}/cst-substitute',
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)
self.assertForbidden(data, item=self.unowned_id)
self.assertBadData(data, item=self.schema_id)
data = {'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}
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)
self.assertBadData(data, item=self.schema_id)
data = {'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}
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)
self.assertBadData(data, item=self.schema_id)
d1 = Constituenta.objects.create(
d1 = self.schema.insert_new(
alias='D1',
schema=self.owned.item,
order=3,
term_raw='@{X2|sing,datv}',
definition_formal='X1'
)
data = {'original': x1.pk, 'substitution': x2.pk, 'transfer_term': True}
response = self.client.patch(
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
data=data, format='json'
)
response = self.execute(data, item=self.schema_id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
d1.refresh_from_db()
@ -342,23 +283,20 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(d1.term_resolved, 'form1')
self.assertEqual(d1.definition_formal, 'X2')
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
def test_create_constituenta_data(self):
data = {
'alias': 'X3',
'cst_type': 'basic',
'cst_type': CstType.BASE,
'convention': '1',
'term_raw': '2',
'definition_formal': '3',
'definition_raw': '4'
}
item = self.owned.item
response = self.client.post(
f'/api/rsforms/{item.id}/cst-create',
data=data, format='json'
)
response = self.execute(data, item=self.schema_id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
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']['term_raw'], '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_resolved'], '4')
@decl_endpoint('/api/rsforms/{item}/cst-delete-multiple', method='patch')
def test_delete_constituenta(self):
schema = self.owned
data = {'items': [1337]}
response = self.client.patch(
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.set_params(item=self.schema_id)
data = {'items': [1337]}
self.assertBadData(data)
x1 = self.schema.insert_new('X1')
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]}
response = self.client.patch(
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
data=data, format='json'
)
response = self.execute(data)
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(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.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]}
response = self.client.patch(
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertBadData(data, item=self.schema_id)
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
def test_move_constituenta(self):
item = self.owned.item
data = {'items': [1337], 'move_to': 1}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-moveto',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.set_params(item=self.schema_id)
data = {'items': [1337], 'move_to': 1}
self.assertBadData(data)
x1 = self.schema.insert_new('X1')
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}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-moveto',
data=data, format='json'
)
response = self.execute(data)
x1.refresh_from_db()
x2.refresh_from_db()
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(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}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-moveto',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertBadData(data)
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
def test_reset_aliases(self):
item = self.owned.item
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)
self.set_params(item=self.schema_id)
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=1)
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=2)
d11 = Constituenta.objects.create(schema=item, alias='D11', cst_type='term', order=3)
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], self.schema_id)
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()
x2.refresh_from_db()
d11.refresh_from_db()
@ -450,103 +375,57 @@ class TestRSFormViewset(APITestCase):
self.assertEqual(d11.order, 3)
self.assertEqual(d11.alias, 'D1')
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertOK()
@decl_endpoint('/api/rsforms/{item}/load-trs', method='patch')
def test_load_trs(self):
schema = self.owned
schema.item.title = 'Test11'
schema.item.save()
x1 = Constituenta.objects.create(schema=schema.item, alias='X1', cst_type='basic', order=1)
self.set_params(item=self.schema_id)
self.schema.item.title = 'Test11'
self.schema.item.save()
x1 = self.schema.insert_new('X1')
work_dir = os.path.dirname(os.path.abspath(__file__))
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
data = {'file': file, 'load_metadata': False}
response = self.client.patch(
f'/api/rsforms/{schema.item.id}/load-trs',
data=data, format='multipart'
)
schema.item.refresh_from_db()
response = self.client.patch(self.endpoint, data=data, format='multipart')
self.schema.item.refresh_from_db()
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(schema.constituents().count(), 25)
self.assertEqual(self.schema.constituents().count(), 25)
self.assertFalse(Constituenta.objects.filter(pk=x1.id).exists())
def test_clone(self):
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)
@decl_endpoint('/api/rsforms/{item}/cst-produce-structure', method='patch')
def test_produce_structure(self):
item = self.owned.item
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=1)
s1 = Constituenta.objects.create(schema=item, alias='S1', cst_type='structure', order=2)
s2 = Constituenta.objects.create(schema=item, alias='S2', cst_type='structure', order=3)
s3 = Constituenta.objects.create(schema=item, alias='S3', cst_type='structure', order=4)
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.set_params(item=self.schema_id)
x1 = self.schema.insert_new('X1')
s1 = self.schema.insert_new(
alias='S1',
definition_formal='(X1×X1)'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'target': x1.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
s2 = self.schema.insert_new(
alias='S2',
definition_formal='invalid'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
data = {'target': s2.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
s3 = self.schema.insert_new(
alias='S3',
definition_formal='X1×(X1×(X1))×(X1×X1)'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
a1 = self.schema.insert_new(
alias='A1',
definition_formal='1=1'
)
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
s1.refresh_from_db()
data = {'target': s1.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
)
response = self.execute({'target': s1.id})
self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema']
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
s3.refresh_from_db()
data = {'target': s3.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
)
response = self.execute({'target': s3.id})
self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema']
items = [item for item in result['items'] if item['id'] in response.data['cst_list']]
@ -572,11 +447,7 @@ class TestRSFormViewset(APITestCase):
# Testing function
f1.refresh_from_db()
data = {'target': f1.id}
response = self.client.patch(
f'/api/rsforms/{item.id}/cst-produce-structure',
data=data, format='json'
)
response = self.execute({'target': f1.id})
self.assertEqual(response.status_code, status.HTTP_200_OK)
result = response.data['schema']
items = [item for item in result['items'] if item['id'] in response.data['cst_list']]

View File

@ -1,109 +1,41 @@
''' Testing views '''
import os
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework.exceptions import ErrorDetail
from rest_framework import status
from apps.users.models import User
from apps.rsform.models import RSForm
from apps.rsform.views import (
convert_to_ascii,
convert_to_math,
parse_expression
)
from .EndpointTester import decl_endpoint, EndpointTester
class TestRSLanguageViews(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
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')
class TestRSLanguageViews(EndpointTester):
''' Test RS language endpoints. '''
@decl_endpoint('/api/rslang/to-ascii', method='post')
def test_convert_to_ascii(self):
data = {'data': '1=1'}
self.assertBadData(data)
data = {'expression': '1=1'}
request = self.factory.post(
'/api/rslang/to-ascii',
data=data, format='json'
)
response = convert_to_ascii(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], r'1 \eq 1')
def test_convert_to_ascii_missing_data(self):
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)
@decl_endpoint('/api/rslang/to-math', method='post')
def test_convert_to_math(self):
data = {'data': r'1 \eq 1'}
self.assertBadData(data)
data = {'expression': r'1 \eq 1'}
request = self.factory.post(
'/api/rslang/to-math',
data=data, format='json'
)
response = convert_to_math(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['result'], r'1=1')
def test_convert_to_math_missing_data(self):
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)
@decl_endpoint('/api/rslang/parse-expression', method='post')
def test_parse_expression(self):
data = {'data': r'1=1'}
self.assertBadData(data)
data = {'expression': r'1=1'}
request = self.factory.post(
'/api/rslang/parse-expression',
data=data, format='json'
)
response = parse_expression(request)
response = self.execute(data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['parseResult'], True)
self.assertEqual(response.data['syntax'], 'math')
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. '''
import io
from typing import cast
from sys import version
from zipfile import ZipFile
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
from rest_framework import status
from apps.users.models import User
from apps.rsform.models import RSForm, Constituenta
from .EndpointTester import decl_endpoint, EndpointTester
class TestVersionViews(APITestCase):
class TestVersionViews(EndpointTester):
''' Testing versioning endpoints. '''
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create(username='UserTest')
self.client = APIClient()
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')
super().setUp()
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user).item
self.unowned = RSForm.create(title='Test2', alias='T2').item
self.x1 = Constituenta.objects.create(
schema=self.owned.item,
schema=self.owned,
alias='X1',
cst_type='basic',
convention='testStart',
order=1
)
@decl_endpoint('/api/rsforms/{schema}/versions/create', method='post')
def test_create_version(self):
invalid_data = {'description': 'test'}
data = {'version': '1.0.0', 'description': 'test'}
invalid_id = 1338
response = self.client.post(
f'/api/rsforms/{invalid_id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
data = {'version': '1.0.0', 'description': 'test'}
response = self.client.post(
f'/api/rsforms/{self.unowned.item.id}/versions/create',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertNotFound(data, schema=invalid_id)
self.assertForbidden(data, schema=self.unowned.id)
self.assertBadData(invalid_data, schema=self.owned.id)
response = self.client.post(
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'
)
response = self.execute(data, schema=self.owned.id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue('version' in response.data)
self.assertTrue('schema' in response.data)
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):
data = {'version': '1.0.0', 'description': 'test'}
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)
version_id = response.data['version']
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
invalid_id = version_id + 1337
invalid_id = 1338
response = self.client.get(f'/api/rsforms/{invalid_id}/versions/{invalid_id}')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
response = self.client.get(f'/api/rsforms/{self.owned.item.id}/versions/{invalid_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.assertNotFound(schema=invalid_id, version=invalid_id)
self.assertNotFound(schema=self.owned.id, version=invalid_id)
self.assertNotFound(schema=invalid_id, version=version_id)
self.assertNotFound(schema=self.unowned.id, version=version_id)
self.owned.item.alias = 'NewName'
self.owned.item.save()
self.owned.alias = 'NewName'
self.owned.save()
self.x1.alias = 'X33'
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.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.assertEqual(response.data['version'], version_id)
@decl_endpoint('/api/versions/{version}', method='get')
def test_access_version(self):
data = {'version': '1.0.0', 'description': 'test'}
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)
version_id = response.data['version']
version_id = self._create_version(data)
invalid_id = version_id + 1337
response = self.client.get(f'/api/versions/{invalid_id}')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertNotFound(version=invalid_id)
self.client.logout()
response = self.client.get(f'/api/versions/{version_id}')
self.set_params(version=version_id)
self.logout()
response = self.execute()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['version'], data['version'])
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(
f'/api/versions/{version_id}',
data=data, format='json'
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
data = {'version': '1.2.0', 'description': 'test1'}
self.method = 'patch'
self.assertForbidden(data)
response = self.client.delete(f'/api/versions/{version_id}')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.method = 'delete'
self.assertForbidden()
self.client.force_authenticate(user=self.user)
data = {'version': '1.1.0', 'description': 'test1'}
response = self.client.patch(
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.method = 'patch'
self.assertOK(data)
response = self.get()
self.assertEqual(response.data['version'], data['version'])
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)
response = self.client.get(f'/api/versions/{version_id}')
response = self.get()
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):
a1 = Constituenta.objects.create(
schema=self.owned.item,
schema=self.owned,
alias='A1',
cst_type='axiom',
definition_formal='X1=X1',
order=2
)
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']
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
a1.definition_formal = 'X1=X2'
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)
loaded_a1 = response.data['items'][1]
self.assertEqual(loaded_a1['definition_formal'], 'X1=X1')
self.assertEqual(loaded_a1['parse']['status'], 'verified')
@decl_endpoint('/api/versions/{version}/export-file', method='get')
def test_export_version(self):
invalid_id = 1338
response = self.client.get(f'/api/versions/{invalid_id}/export-file')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertNotFound(version=invalid_id)
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']
response = self.client.get(f'/api/versions/{version_id}/export-file')
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
response = self.get(version=version_id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
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 ZipFile(stream, 'r') as zipped_file:
self.assertIsNone(zipped_file.testzip())
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()
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 == '':
return text
pos_input: int = 0