forked from mathialm/secfit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
unknown
committed
Apr 3, 2025
1 parent
2cc5345
commit 2b0f204
Showing
17 changed files
with
279 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| file_content |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| from django.test import TestCase | ||
| from rest_framework.test import APIClient | ||
| from django.contrib.auth import get_user_model | ||
| from django.urls import reverse | ||
| from workouts.models import Exercise, Workout | ||
| from users.models import AthleteFile | ||
| from datetime import datetime | ||
| from django.utils.timezone import make_aware | ||
| from django.core.files.uploadedfile import SimpleUploadedFile | ||
| import json | ||
|
|
||
| User = get_user_model() | ||
|
|
||
| # Test Case 001: Focuses on workout creation functionality | ||
| # Verifies that workouts can be created with valid inputs and proper relationships | ||
| class WorkoutCreationTest(TestCase): | ||
| """TC_001: Equivalence class testing for workout creation""" | ||
| def setUp(self): | ||
| # Setup test athlete user and authentication token | ||
| self.client = APIClient() | ||
| self.athlete = User.objects.create_user( | ||
| username='athlete', | ||
| password='athletepass123', | ||
| email='athlete@example.com', | ||
| isCoach=False | ||
| ) | ||
| # Get JWT token for athlete | ||
| response = self.client.post( | ||
| reverse('token_obtain_pair'), | ||
| {'username': 'athlete', 'password': 'athletepass123'}, | ||
| format='json' | ||
| ) | ||
| self.token = response.data['access'] | ||
| self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}') | ||
|
|
||
| # Create test exercise to use in workout | ||
| self.exercise = Exercise.objects.create( | ||
| name="Squats", | ||
| description="Bodyweight squats", | ||
| unit="reps" | ||
| ) | ||
|
|
||
| # Tests successful workout creation with all required valid fields | ||
| def test_valid_workout_creation(self): | ||
| """Verify workout creation with valid inputs""" | ||
| data = { | ||
| 'name': 'Morning Run', | ||
| 'date': make_aware(datetime(2025, 4, 1)).isoformat(), | ||
| 'exercise_instances': [{ | ||
| 'exercise': f'http://testserver/api/exercises/{self.exercise.id}/', | ||
| 'sets': 3, | ||
| 'number': 1, # Added required 'number' field | ||
| 'units': 'reps' | ||
| }], | ||
| 'notes': 'Felt strong today', | ||
| 'visibility': 'PU', | ||
| 'owner': f'http://testserver/api/users/{self.athlete.id}/' | ||
| } | ||
|
|
||
| response = self.client.post( | ||
| reverse('workout-list'), | ||
| data=data, | ||
| format='json' | ||
| ) | ||
|
|
||
| self.assertEqual(response.status_code, 201, response.data) | ||
| self.assertTrue(Workout.objects.filter(name='Morning Run').exists()) | ||
|
|
||
| # Test Case 002: Focuses on user registration validation | ||
| # Verifies password rules and proper user type assignment | ||
| class UserRegistrationTest(TestCase): | ||
| """TC_002: Boundary value testing for password/user type validation""" | ||
| def setUp(self): | ||
| # Setup API client and registration endpoint | ||
| self.client = APIClient() | ||
| self.register_url = reverse('user-list') | ||
|
|
||
| # Tests successful user registration with valid credentials | ||
| def test_valid_registration(self): | ||
| """Verify system enforces password rules and user type""" | ||
| data = { | ||
| 'username': 'TestUser', | ||
| 'password': 'SecurePass123!', | ||
| 'password1': 'SecurePass123!', | ||
| 'email': 'test@example.com', | ||
| 'first_name': 'Test', | ||
| 'last_name': 'User', | ||
| 'isCoach': False, | ||
| 'athletes': [], | ||
| 'workouts': [], | ||
| 'coach_files': [], | ||
| 'athlete_files': [] | ||
| } | ||
|
|
||
| response = self.client.post( | ||
| self.register_url, | ||
| data=data, | ||
| format='json' | ||
| ) | ||
|
|
||
| self.assertEqual(response.status_code, 201, response.data) | ||
| user = User.objects.get(username='TestUser') | ||
| self.assertEqual(user.email, 'test@example.com') | ||
| self.assertFalse(user.isCoach) | ||
|
|
||
| # Test Case 003: Focuses on workout visibility permissions | ||
| # Verifies access control for private workouts | ||
| class WorkoutVisibilityTest(TestCase): | ||
| """TC_003: Robust boundary value testing for private workouts""" | ||
| def setUp(self): | ||
| # Setup test athlete and private workout | ||
| self.client = APIClient() | ||
| self.athlete = User.objects.create_user( | ||
| username='athlete', | ||
| password='athletepass123', | ||
| isCoach=False | ||
| ) | ||
| self.workout = Workout.objects.create( | ||
| name='Private Workout', | ||
| owner=self.athlete, | ||
| visibility='PR', | ||
| date=make_aware(datetime(2025, 4, 1)), | ||
| notes='Test workout' | ||
| ) | ||
|
|
||
| # Tests that unauthenticated users cannot access private workouts | ||
| def test_visitor_access_private_workout(self): | ||
| """Verify visitors can't access private workouts""" | ||
| # Clear any authentication | ||
| self.client.credentials() | ||
| response = self.client.get( | ||
| reverse('workout-detail', kwargs={'pk': self.workout.id}) | ||
| ) | ||
| self.assertEqual(response.status_code, 401, | ||
| "Visitors should get 401 Unauthorized") | ||
|
|
||
| # Test Case 004: Focuses on file upload functionality | ||
| # Verifies file type validation and coach-athlete relationship | ||
| class FileUploadTest(TestCase): | ||
| """TC_004: Special value testing for file uploads""" | ||
| def setUp(self): | ||
| # Setup coach and athlete users with authentication | ||
| self.client = APIClient() | ||
| self.coach = User.objects.create_user( | ||
| username='coach', | ||
| password='coachpass123', | ||
| isCoach=True | ||
| ) | ||
| self.athlete = User.objects.create_user( | ||
| username='athlete', | ||
| password='athletepass123', | ||
| isCoach=False | ||
| ) | ||
| # Get JWT token for coach | ||
| response = self.client.post( | ||
| reverse('token_obtain_pair'), | ||
| {'username': 'coach', 'password': 'coachpass123'}, | ||
| format='json' | ||
| ) | ||
| self.token = response.data['access'] | ||
| self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}') | ||
|
|
||
| # Tests file upload with different file types | ||
| def test_file_upload_validation(self): | ||
| """Verify file upload works with different file types""" | ||
| # First, ensure coach is assigned to athlete | ||
| self.athlete.coach = self.coach | ||
| self.athlete.save() | ||
|
|
||
| # Test with valid JPEG file (should succeed) | ||
| jpg_file = SimpleUploadedFile( | ||
| "workout.jpg", | ||
| b"file_content", | ||
| content_type="image/jpeg" | ||
| ) | ||
| response = self.client.post( | ||
| reverse('athlete-file-list'), | ||
| { | ||
| 'file': jpg_file, | ||
| 'athlete': f'http://testserver/api/users/{self.athlete.id}/', | ||
| 'owner': f'http://testserver/api/users/{self.coach.id}/' | ||
| }, | ||
| format='multipart' | ||
| ) | ||
| self.assertEqual(response.status_code, 201, | ||
| f"Expected 201, got {response.status_code}. Response: {response.data}") | ||
|
|
||
| # Test with potentially dangerous EXE file (reveals security issue) | ||
| exe_file = SimpleUploadedFile( | ||
| "workout.exe", | ||
| b"file_content", | ||
| content_type="application/octet-stream" | ||
| ) | ||
| response = self.client.post( | ||
| reverse('athlete-file-list'), | ||
| { | ||
| 'file': exe_file, | ||
| 'athlete': f'http://testserver/api/users/{self.athlete.id}/', | ||
| 'owner': f'http://testserver/api/users/{self.coach.id}/' | ||
| }, | ||
| format='multipart' | ||
| ) | ||
| self.assertEqual(response.status_code, 201, | ||
| "Currently accepts all file types since validator isn't properly configured") | ||
|
|
||
| class ExerciseValidationTest(TestCase): | ||
| """TC_005: Testing exercise creation""" | ||
| def setUp(self): | ||
| self.client = APIClient() | ||
| self.coach = User.objects.create_user( | ||
| username='coach', | ||
| password='coachpass123', | ||
| isCoach=True | ||
| ) | ||
| # Get JWT token for coach | ||
| response = self.client.post( | ||
| reverse('token_obtain_pair'), | ||
| {'username': 'coach', 'password': 'coachpass123'}, | ||
| format='json' | ||
| ) | ||
| self.token = response.data['access'] | ||
| self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}') | ||
|
|
||
| def test_exercise_creation_with_any_unit(self): | ||
| """Verify system currently accepts any unit value""" | ||
| data = { | ||
| 'name': 'Custom Exercise', | ||
| 'description': 'This tests unit validation', | ||
| 'unit': 'unexpected_unit' # Should pass since validation isn't enforced | ||
| } | ||
|
|
||
| response = self.client.post( | ||
| reverse('exercise-list'), | ||
| data=data, | ||
| format='json' | ||
| ) | ||
|
|
||
| self.assertEqual(response.status_code, 201, | ||
| "Currently accepts any unit value") | ||
| self.assertTrue(Exercise.objects.filter(name='Custom Exercise').exists(), | ||
| "Exercise should be created regardless of unit value") |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Generated by Django 5.2 on 2025-04-03 20:28 | ||
|
|
||
| import users.models | ||
| import users.validators | ||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('users', '0003_user_specialism'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='athletefile', | ||
| name='file', | ||
| field=models.FileField(upload_to=users.models.athlete_directory_path, validators=[users.validators.FileValidator(allowed_extensions='', allowed_mimetypes='', max_size=5242880)]), | ||
| ), | ||
| ] |