From 5fee8085e791c9db53e62753b8678c057efb70e4 Mon Sep 17 00:00:00 2001 From: RosuGabriel Date: Sun, 26 Jan 2025 18:06:01 +0200 Subject: [PATCH 01/11] Updated diagrams --- diagrams/code/code_diagram.puml | 57 +++++++++++++++++++++++++++ diagrams/code/component_diagram.puml | 28 ++++++------- diagrams/code_diagram.pdf | Bin 0 -> 118104 bytes diagrams/component_diagram.pdf | Bin 38901 -> 49346 bytes 4 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 diagrams/code/code_diagram.puml create mode 100644 diagrams/code_diagram.pdf diff --git a/diagrams/code/code_diagram.puml b/diagrams/code/code_diagram.puml new file mode 100644 index 0000000..816531c --- /dev/null +++ b/diagrams/code/code_diagram.puml @@ -0,0 +1,57 @@ +@startuml diagrame +!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml +!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml +!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml + +' Styles +skinparam rectangle { + BorderColor Black + BorderStyle Dotted + Padding 35 +} + +' Content +rectangle "API Application" as boundary { + ' Controllers + Component(accountController, "User Controller","C#", "Handles user authentication requests and manages user sessions.") #89CFF0 + Component(noteController, "Note Controller","C#", "Manages requests related to notes, including creation, retrieval, and deletion.") #89CFF0 + Component(groupController, "Group Controller","C#", "Manages requests related to groups, including creation, members management, and deletion.") #89CFF0 + ' Services + Component(accountService, "Account Service", "C#", "Processes business logic related to user accounts and authentication.") #89CFF0 + Component(noteService, "Note Service", "C#", "Handles business logic for notes management and interacts with the repository layer.") #89CFF0 + Component(groupService, "Group Service", "C#", "Handles business logic for groups management and interacts with the repository layer.") #89CFF0 + Component(tokenService, "Token Service", "C#", "Handles business logic for tokens management and interacts with the repository layer.") #89CFF0 + ' Repositories + Component(noteRepository, "Note Repository", "C#", "Interacts with the database for CRUD operations on notes.") #89CFF0 + Component(accountRepository, "Account Repository", "C#", "Manages data persistence and retrieval for user accounts.") #89CFF0 + Component(groupRepository, "Group Repository", "C#", "Interacts with the database for CRUD operations on groups.") #89CFF0 + Component(tokenRepository, "Token Repository", "C#", "Interacts with the database for CRUD operations on tokens.") #89CFF0 + ' Helpers + Component(encrypter, "Encrypter", "C#", "Encrypts and decrypts given input.") #89CFF0 + Component(exception, "ActionResponseExceptions", "C#", "Creates exceptions associated with a status code.") #89CFF0 +} + +ContainerDb(dataBase, "App Database", "Microsoft SQL Server", "Stores user details, notes, and specific tables to facilitate collections of notes.") #23282a + +Rel(noteController, noteService, " Uses") +Rel(groupController, groupService, " Uses") +Rel(accountController, accountService, " Uses") + +Rel(noteService, exception, "Throws") +Rel(accountService, exception, "Throws") +Rel(groupService, exception, "Throws") +Rel(tokenService, exception, "Throws") + +Rel(noteService, encrypter, "Encrypts/decrypts notes using") +Rel(encrypter, noteRepository, "Requests database action to") +Rel(accountService, accountRepository, "Requests database action to") +Rel(groupService, groupRepository, "Requests database action to") +Rel(accountService, tokenService, " Uses") +Rel(tokenService, tokenRepository, "Requests database action to") + +Rel(accountRepository, dataBase, " Reads from and writes to") +Rel(noteRepository, dataBase, " Reads from and writes to") +Rel(groupRepository, dataBase, " Reads from and writes to") +Rel(tokenRepository, dataBase, " Reads from and writes to") + +@enduml diff --git a/diagrams/code/component_diagram.puml b/diagrams/code/component_diagram.puml index 8a6fee6..ff40b68 100644 --- a/diagrams/code/component_diagram.puml +++ b/diagrams/code/component_diagram.puml @@ -15,30 +15,24 @@ Container(mobileApp, "Mobile App", "React Native", "Provides notes manipulation rectangle "API Application" as boundary { ' Controllers - Component(accountController, "Account Controller","C#", "Handles user authentication requests and manages user sessions.") #89CFF0 + Component(accountController, "User Controller","C#", "Handles user authentication requests and manages user sessions.") #89CFF0 Component(notesController, "Notes Controller","C#", "Manages requests related to notes, including creation, retrieval, and deletion.") #89CFF0 + Component(groupsController, "Groups Controller","C#", "Manages requests related to groups, including creation, members management, and deletion.") #89CFF0 + ' Services - Component(accountService, "Account Service", "C#", "Processes business logic related to user accounts and authentication.") #89CFF0 - Component(notesService, "Notes Service", "C#", "Handles business logic for notes management and interacts with the repository layer.") #89CFF0 - Component(notificationService, "Notification Service", "C#", "Takes care of sending notifications when certain events occur within the application.") #89CFF0 - ' Repositories - Component(notesRepository, "Notes Repository", "C#", "Interacts with the database for CRUD operations on notes.") #89CFF0 - Component(accountRepository, "Account Repository", "C#", "Manages data persistence and retrieval for user accounts.") #89CFF0 + Component(services, "API Services", "C#", "Contains business logic for the actions requiered by controllers.") #89CFF0 } ContainerDb(dataBase, "App Database", "Microsoft SQL Server", "Stores user details, notes, and specific tables to facilitate collections of notes.") #23282a ' Relationships -Rel(mobileApp, accountController, " Makes API calls to") -Rel(mobileApp, notesController, " Makes API calls to") - -Rel(notesController, notesService, " Uses") -Rel(notesController, notificationService, " Uses") -Rel(accountController, accountService, " Uses") +Rel(mobileApp, accountController, "Makes API calls to") +Rel(mobileApp, notesController, "Makes API calls to") +Rel(mobileApp, groupsController, "Makes API calls to") -Rel(notesService, notesRepository, "Requests database action to") -Rel(accountService, accountRepository, "Requests database action to") +Rel(accountController, services, "Solves requests using") +Rel(notesController, services, "Solves requests using") +Rel(groupsController, services, "Solves requests using") -Rel(accountRepository, dataBase, " Reads from and writes to") -Rel(notesRepository, dataBase, " Reads from and writes to") +Rel(services, dataBase, "Gets data from and stores to") @enduml diff --git a/diagrams/code_diagram.pdf b/diagrams/code_diagram.pdf new file mode 100644 index 0000000000000000000000000000000000000000..414ce2a976c64c149bcf33ec622feb16e5454ef1 GIT binary patch literal 118104 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 YaqT(L=nH&;=fP=U5Yp1S4;Uc+0~5YDuK)l5 literal 0 HcmV?d00001 diff --git a/diagrams/component_diagram.pdf b/diagrams/component_diagram.pdf index 35fabce0a5dff7e608b949a58bff5cd7aa4df567..e830b21b86e3e234faabdffc9592cd720e9046eb 100644 GIT binary patch literal 49346 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 CEp*HP literal 38901 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≠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 From e400a787b0d8a3e4b1eda222cd135451ed6f07e9 Mon Sep 17 00:00:00 2001 From: Pericica Medeea Maria Date: Tue, 28 Jan 2025 00:27:57 +0200 Subject: [PATCH 02/11] tests for register in user controller --- .../CollectifyAPI.Tests.csproj | 28 + .../ControllersTests/UserControllerTests.cs | 95 ++++ CollectifyAPI/CollectifyAPI.sln | 6 + .../20250127171458_mig3.Designer.cs | 485 ++++++++++++++++++ .../Migrations/20250127171458_mig3.cs | 98 ++++ .../ApplicationDbContextModelSnapshot.cs | 16 +- CollectifyAPI/CollectifyAPI/appsettings.json | 2 +- 7 files changed, 721 insertions(+), 9 deletions(-) create mode 100644 CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj create mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs create mode 100644 CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.Designer.cs create mode 100644 CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.cs diff --git a/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj new file mode 100644 index 0000000..7317f9e --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs new file mode 100644 index 0000000..2bf571d --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs @@ -0,0 +1,95 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; +using CollectifyAPI.Controllers; +using CollectifyAPI.Models; +using CollectifyAPI.Services; +using CollectifyAPI.Dtos; + +public class UserControllerTests +{ + private readonly Mock> _userManagerMock; + private readonly Mock> _signInManagerMock; + private readonly Mock _tokenServiceMock; + private readonly Mock _accountServiceMock; + private readonly Mock _httpContextAccessorMock; + private readonly UserController _userController; + + public UserControllerTests() + { + _userManagerMock = new Mock>( + new Mock>().Object, + null, null, null, null, null, null, null, null + ); + + _signInManagerMock = new Mock>( + _userManagerMock.Object, + new Mock().Object, + new Mock>().Object, + null, null, null, null + ); + + _tokenServiceMock = new Mock(null, null); + _accountServiceMock = new Mock(null, null); + _httpContextAccessorMock = new Mock(); + + _userController = new UserController( + _signInManagerMock.Object, + _userManagerMock.Object, + _tokenServiceMock.Object, + _accountServiceMock.Object, + _httpContextAccessorMock.Object + ); + } + + [Fact] + public async Task Register_ValidRequest_ReturnsOk() + { + // Arrange + var userCreditentials = new UserCreditentials { Email = "test@example.com", Password = "Password123" }; + _accountServiceMock.Setup(service => service.RegisterAsync(userCreditentials, _userManagerMock.Object)) + .Returns(Task.CompletedTask); + + // Act + var result = await _userController.Register(userCreditentials); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(200, okResult.StatusCode); + } + + [Fact] + public async Task Register_InvalidModelState_ReturnsBadRequest() + { + // Arrange + _userController.ModelState.AddModelError("Email", "The Email field is required."); + var userCreditentials = new UserCreditentials(); + + // Act + var result = await _userController.Register(userCreditentials); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.Equal(400, badRequestResult.StatusCode); + } + + [Fact] + public async Task Register_ServiceThrowsException_ReturnsInternalServerError() + { + // Arrange + var userCreditentials = new UserCreditentials { Email = "test@example.com", Password = "Password123" }; + _accountServiceMock.Setup(service => service.RegisterAsync(userCreditentials, _userManagerMock.Object)) + .ThrowsAsync(new System.Exception("Unexpected error")); + + // Act + var result = await _userController.Register(userCreditentials); + + // Assert + var statusCodeResult = Assert.IsType(result); + Assert.Equal(500, statusCodeResult.StatusCode); + Assert.Contains("Unexpected error", statusCodeResult.Value.ToString()); + } +} diff --git a/CollectifyAPI/CollectifyAPI.sln b/CollectifyAPI/CollectifyAPI.sln index e4d3079..c39463e 100644 --- a/CollectifyAPI/CollectifyAPI.sln +++ b/CollectifyAPI/CollectifyAPI.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.11.35431.28 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI", "CollectifyAPI\CollectifyAPI.csproj", "{6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI.Tests", "CollectifyAPI.test\CollectifyAPI.Tests.csproj", "{3467EC4E-4CB7-4F40-8870-907C40FA7F30}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.Build.0 = Release|Any CPU + {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.Designer.cs b/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.Designer.cs new file mode 100644 index 0000000..921cc13 --- /dev/null +++ b/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.Designer.cs @@ -0,0 +1,485 @@ +// +using System; +using CollectifyAPI.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CollectifyAPI.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250127171458_mig3")] + partial class mig3 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CollectifyAPI.Models.AppUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("AvatarPath") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasData( + new + { + Id = "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b", + AccessFailedCount = 0, + ConcurrencyStamp = "71880f39-b889-4e7d-932b-9b641cd68ef8", + Email = "admin@collectify-app.ro", + EmailConfirmed = true, + LockoutEnabled = false, + NormalizedEmail = "ADMIN@COLLECTIFY-APP.RO", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAELq+xsw/RC7ONGQoVsWXlafynb61y8RrzQLIQt09I7nVJMWqRkX+uLazYz5yi6LrJQ==", + PhoneNumberConfirmed = false, + SecurityStamp = "5261ed1f-67c1-49d9-aabb-3c2475446dfc", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("CollectifyAPI.Models.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.GroupMember", b => + { + b.Property("MemberId") + .HasColumnType("nvarchar(450)"); + + b.Property("GroupId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("MemberId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMembers"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.Note", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnType("nvarchar(450)"); + + b.Property("GroupId") + .HasColumnType("uniqueidentifier"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.HasIndex("GroupId"); + + b.ToTable("Notes"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("UserRefreshTokens"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = "b8768963-39fb-4894-a8b3-523287661807", + Name = "admin", + NormalizedName = "ADMIN" + }, + new + { + Id = "5f4b3f8d-cbe5-4c17-9eca-19abfa58c7be", + Name = "user", + NormalizedName = "USER" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + + b.HasData( + new + { + UserId = "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b", + RoleId = "b8768963-39fb-4894-a8b3-523287661807" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("CollectifyAPI.Models.Group", b => + { + b.HasOne("CollectifyAPI.Models.AppUser", "Creator") + .WithMany("OwnedGroups") + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.GroupMember", b => + { + b.HasOne("CollectifyAPI.Models.Group", "Group") + .WithMany("Members") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CollectifyAPI.Models.AppUser", "Member") + .WithMany("Groups") + .HasForeignKey("MemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("Member"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.Note", b => + { + b.HasOne("CollectifyAPI.Models.AppUser", "Creator") + .WithMany("Notes") + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("CollectifyAPI.Models.Group", "Group") + .WithMany("Notes") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Creator"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CollectifyAPI.Models.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CollectifyAPI.Models.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CollectifyAPI.Models.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CollectifyAPI.Models.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectifyAPI.Models.AppUser", b => + { + b.Navigation("Groups"); + + b.Navigation("Notes"); + + b.Navigation("OwnedGroups"); + }); + + modelBuilder.Entity("CollectifyAPI.Models.Group", b => + { + b.Navigation("Members"); + + b.Navigation("Notes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.cs b/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.cs new file mode 100644 index 0000000..56b18ff --- /dev/null +++ b/CollectifyAPI/CollectifyAPI/Migrations/20250127171458_mig3.cs @@ -0,0 +1,98 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CollectifyAPI.Migrations +{ + /// + public partial class mig3 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "3d17fc61-5b66-4127-9fa3-443ea26484d7"); + + migrationBuilder.DeleteData( + table: "AspNetUserRoles", + keyColumns: new[] { "RoleId", "UserId" }, + keyValues: new object[] { "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1", "a761f656-6c13-4bf1-ab4c-df080af0b75b" }); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1"); + + migrationBuilder.DeleteData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: "a761f656-6c13-4bf1-ab4c-df080af0b75b"); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "5f4b3f8d-cbe5-4c17-9eca-19abfa58c7be", null, "user", "USER" }, + { "b8768963-39fb-4894-a8b3-523287661807", null, "admin", "ADMIN" } + }); + + migrationBuilder.InsertData( + table: "AspNetUsers", + columns: new[] { "Id", "AccessFailedCount", "AvatarPath", "ConcurrencyStamp", "Email", "EmailConfirmed", "LockoutEnabled", "LockoutEnd", "Nickname", "NormalizedEmail", "NormalizedUserName", "PasswordHash", "PhoneNumber", "PhoneNumberConfirmed", "SecurityStamp", "TwoFactorEnabled", "UserName" }, + values: new object[] { "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b", 0, null, "71880f39-b889-4e7d-932b-9b641cd68ef8", "admin@collectify-app.ro", true, false, null, null, "ADMIN@COLLECTIFY-APP.RO", "ADMIN", "AQAAAAIAAYagAAAAELq+xsw/RC7ONGQoVsWXlafynb61y8RrzQLIQt09I7nVJMWqRkX+uLazYz5yi6LrJQ==", null, false, "5261ed1f-67c1-49d9-aabb-3c2475446dfc", false, "admin" }); + + migrationBuilder.InsertData( + table: "AspNetUserRoles", + columns: new[] { "RoleId", "UserId" }, + values: new object[] { "b8768963-39fb-4894-a8b3-523287661807", "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "5f4b3f8d-cbe5-4c17-9eca-19abfa58c7be"); + + migrationBuilder.DeleteData( + table: "AspNetUserRoles", + keyColumns: new[] { "RoleId", "UserId" }, + keyValues: new object[] { "b8768963-39fb-4894-a8b3-523287661807", "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b" }); + + migrationBuilder.DeleteData( + table: "AspNetRoles", + keyColumn: "Id", + keyValue: "b8768963-39fb-4894-a8b3-523287661807"); + + migrationBuilder.DeleteData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b"); + + migrationBuilder.InsertData( + table: "AspNetRoles", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "3d17fc61-5b66-4127-9fa3-443ea26484d7", null, "user", "USER" }, + { "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1", null, "admin", "ADMIN" } + }); + + migrationBuilder.InsertData( + table: "AspNetUsers", + columns: new[] { "Id", "AccessFailedCount", "AvatarPath", "ConcurrencyStamp", "Email", "EmailConfirmed", "LockoutEnabled", "LockoutEnd", "Nickname", "NormalizedEmail", "NormalizedUserName", "PasswordHash", "PhoneNumber", "PhoneNumberConfirmed", "SecurityStamp", "TwoFactorEnabled", "UserName" }, + values: new object[] { "a761f656-6c13-4bf1-ab4c-df080af0b75b", 0, null, "fd17ff01-a947-4281-b185-1f9da4c9ab61", "admin@collectify-app.ro", true, false, null, null, "ADMIN@COLLECTIFY-APP.RO", "ADMIN", "AQAAAAIAAYagAAAAEKb9XHnT5imT1srscplGUu5iQfPqeg7DbOwDCT0zBBUxscpVFd0fGtke82GLOq3Njg==", null, false, "9c5c5f6d-d447-425e-a973-d747b2e38619", false, "admin" }); + + migrationBuilder.InsertData( + table: "AspNetUserRoles", + columns: new[] { "RoleId", "UserId" }, + values: new object[] { "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1", "a761f656-6c13-4bf1-ab4c-df080af0b75b" }); + } + } +} diff --git a/CollectifyAPI/CollectifyAPI/Migrations/ApplicationDbContextModelSnapshot.cs b/CollectifyAPI/CollectifyAPI/Migrations/ApplicationDbContextModelSnapshot.cs index 9f061ad..0f87173 100644 --- a/CollectifyAPI/CollectifyAPI/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/CollectifyAPI/CollectifyAPI/Migrations/ApplicationDbContextModelSnapshot.cs @@ -95,17 +95,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "a761f656-6c13-4bf1-ab4c-df080af0b75b", + Id = "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b", AccessFailedCount = 0, - ConcurrencyStamp = "fd17ff01-a947-4281-b185-1f9da4c9ab61", + ConcurrencyStamp = "71880f39-b889-4e7d-932b-9b641cd68ef8", Email = "admin@collectify-app.ro", EmailConfirmed = true, LockoutEnabled = false, NormalizedEmail = "ADMIN@COLLECTIFY-APP.RO", NormalizedUserName = "ADMIN", - PasswordHash = "AQAAAAIAAYagAAAAEKb9XHnT5imT1srscplGUu5iQfPqeg7DbOwDCT0zBBUxscpVFd0fGtke82GLOq3Njg==", + PasswordHash = "AQAAAAIAAYagAAAAELq+xsw/RC7ONGQoVsWXlafynb61y8RrzQLIQt09I7nVJMWqRkX+uLazYz5yi6LrJQ==", PhoneNumberConfirmed = false, - SecurityStamp = "9c5c5f6d-d447-425e-a973-d747b2e38619", + SecurityStamp = "5261ed1f-67c1-49d9-aabb-3c2475446dfc", TwoFactorEnabled = false, UserName = "admin" }); @@ -239,13 +239,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1", + Id = "b8768963-39fb-4894-a8b3-523287661807", Name = "admin", NormalizedName = "ADMIN" }, new { - Id = "3d17fc61-5b66-4127-9fa3-443ea26484d7", + Id = "5f4b3f8d-cbe5-4c17-9eca-19abfa58c7be", Name = "user", NormalizedName = "USER" }); @@ -340,8 +340,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - UserId = "a761f656-6c13-4bf1-ab4c-df080af0b75b", - RoleId = "731fbe7c-3d4f-42c1-92a7-efbc29b32fd1" + UserId = "021b4677-42ee-4a0d-91a6-b1e93b1f1e3b", + RoleId = "b8768963-39fb-4894-a8b3-523287661807" }); }); diff --git a/CollectifyAPI/CollectifyAPI/appsettings.json b/CollectifyAPI/CollectifyAPI/appsettings.json index 374406f..2f37cff 100644 --- a/CollectifyAPI/CollectifyAPI/appsettings.json +++ b/CollectifyAPI/CollectifyAPI/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CollectifyDatabase;Trusted_Connection=True;MultipleActiveResultSets=true" + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CollectifyDatabase2;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { From e5f3054019820ee4ba0d525d197baf6f27d192c5 Mon Sep 17 00:00:00 2001 From: Liana Glazov Date: Wed, 29 Jan 2025 16:28:27 +0200 Subject: [PATCH 03/11] tests for the methods in user and group controllers --- .../ControllersTests/GroupControllerTests.cs | 252 ++++++++++++++++++ .../ControllersTests/UserControllerTests.cs | 128 +++++++++ CollectifyAPI/CollectifyAPI.sln | 8 +- .../CollectifyAPI/Services/AccountService.cs | 10 +- .../CollectifyAPI/Services/GroupService.cs | 18 +- 5 files changed, 395 insertions(+), 21 deletions(-) create mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs new file mode 100644 index 0000000..4daa418 --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs @@ -0,0 +1,252 @@ +using Moq; +using Xunit; +using Microsoft.AspNetCore.Mvc; +using CollectifyAPI.Controllers; +using CollectifyAPI.Services; +using CollectifyAPI.Models; +using CollectifyAPI.Dtos; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using System.Security.Claims; +using System; +using CollectifyAPI.Data; + +namespace CollectifyAPI.Tests +{ + public class GroupControllerTests + { + private readonly Mock _mockGroupService; + private readonly Mock _mockHttpContextAccessor; + private readonly GroupController _groupController; + + public GroupControllerTests() + { + _mockGroupService = new Mock(MockBehavior.Strict, null, null, null); + _mockHttpContextAccessor = new Mock(); + _groupController = new GroupController(_mockGroupService.Object, _mockHttpContextAccessor.Object); + } + + [Fact] + public async Task CreateGroup_ValidRequest_ReturnsOk() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var newGroup = new Group { Id = Guid.NewGuid(), Name = "Test Group" }; + + _mockGroupService.Setup(service => service.CreateGroupAsync(newGroup, It.IsAny())) + .ReturnsAsync(new SimpleGroup { Id = Guid.NewGuid(), Name = newGroup.Name }); + + // Act + var result = await _groupController.CreateGroup(newGroup); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(newGroup.Name, returnValue.Name); + } + + + + [Fact] + public async Task CreateGroup_InvalidModelState_ReturnsBadRequest() + { + // Arrange + _groupController.ModelState.AddModelError("Name", "Required"); + + // Act + var result = await _groupController.CreateGroup(new Group()); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task UpdateGroup_GroupDoesNotExist_ReturnsNotFound() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var group = new Group { Id = Guid.NewGuid(), Name = "Updated Group" }; + _mockGroupService.Setup(service => service.UpdateGroupAsync(group, userId)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("Group not found!")); + + // Act + var result = await _groupController.UpdateGroup(group); + + // Assert + var statusCodeResult = Assert.IsType(result); + Assert.Equal(404, statusCodeResult.StatusCode); + Assert.Equal("Group not found!", statusCodeResult.Value); + } + + [Fact] + public async Task UpdateGroup_NotTheOwner_ReturnsForbiddenAccess() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var group = new Group { Id = Guid.NewGuid(), Name = "Updated Group" }; + _mockGroupService.Setup(service => service.UpdateGroupAsync(group, userId)) + .ThrowsAsync(new ActionResponseExceptions.ForbiddenAccessException("You are not the owner of this group!")); + + // Act + var result = await _groupController.UpdateGroup(group); + + // Assert + var statusCodeResult = Assert.IsType(result); + Assert.Equal(403, statusCodeResult.StatusCode); + Assert.Equal("You are not the owner of this group!", statusCodeResult.Value); + } + [Fact] + public async Task UpdateGroup_ValidRequest_ReturnsOk() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var group = new Group { Id = Guid.NewGuid(), Name = "Updated Group" }; + _mockGroupService.Setup(service => service.UpdateGroupAsync(group, userId)) + .ReturnsAsync(new SimpleGroup { Id = Guid.NewGuid(), Name = group.Name }); + + // Act + var result = await _groupController.UpdateGroup(group); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(group.Name, returnValue.Name); + } + + [Fact] + public async Task DeleteGroup_ValidRequest_ReturnsOk() + { + // Arrange + var groupId = Guid.NewGuid(); + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + _mockGroupService.Setup(service => service.DeleteGroupAsync(groupId, userId)) + .Returns(Task.CompletedTask); + + // Act + var result = await _groupController.DeleteGroup(groupId); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task AddMemberToGroup_InvalidModelState_ReturnsBadRequest() + { + // Arrange + var controller = new GroupController(_mockGroupService.Object, _mockHttpContextAccessor.Object); + controller.ModelState.AddModelError("error", "Invalid data"); + + // Act + var result = await controller.AddMemberToGroup(new GroupMember()); + + // Assert + Assert.IsType(result); + var badRequestResult = result as BadRequestObjectResult; + Assert.NotNull(badRequestResult); + Assert.IsType(badRequestResult.Value); + } + + [Fact] + public async Task AddMemberToGroup_ValidRequest_ReturnsOk() + { + // Arrange + var groupMember = new GroupMember { MemberId = "user123", GroupId = Guid.NewGuid() }; + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); // Mocking HttpContext + + _mockGroupService.Setup(service => service.AddMemberToGroupAsync(groupMember)) + .Returns(Task.CompletedTask); + + // Act + var result = await _groupController.AddMemberToGroup(groupMember); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task GetMembersByGroupId_ValidRequest_ReturnsOk() + { + // Arrange + var groupId = Guid.NewGuid(); + var userId = "user123"; + + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + _mockGroupService.Setup(service => service.GetMembersByGroupIdAsync(groupId)) + .ReturnsAsync(new List()); + + // Act + var result = await _groupController.GetMembersByGroupId(groupId); + + // Assert + var okResult = Assert.IsType(result); + Assert.IsType>(okResult.Value); + } + + [Fact] + public async Task RemoveMemberFromGroup_ValidRequest_ReturnsOk() + { + // Arrange + var groupMember = new GroupMember {MemberId = "user123", GroupId = Guid.NewGuid()}; + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); // Mocking HttpContext + + _mockGroupService.Setup(service => service.RemoveMemberFromGroupAsync(groupMember)) + .Returns(Task.CompletedTask); + + // Act + var result = await _groupController.RemoveMemberFromGroup(groupMember); + + // Assert + Assert.IsType(result); + } + + + [Fact] + public async Task GetGroupById_ValidRequest_ReturnsOk() + { + // Arrange + var groupId = Guid.NewGuid(); + var userId = "user123"; + var group = new Group { Id = groupId, Name = "Updated Group" }; + + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + _mockGroupService.Setup(service => service.GetGroupByIdAsync(groupId, userId)) + .ReturnsAsync(new SimpleGroup { Id = Guid.NewGuid(), Name = group.Name }); + + // Act + var result = await _groupController.GetGroupById(groupId); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(group.Name, returnValue.Name); + } + } +} diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs index 2bf571d..243946d 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/UserControllerTests.cs @@ -8,6 +8,8 @@ using CollectifyAPI.Models; using CollectifyAPI.Services; using CollectifyAPI.Dtos; +using System.Security.Claims; +using CollectifyAPI.Data; public class UserControllerTests { @@ -92,4 +94,130 @@ public async Task Register_ServiceThrowsException_ReturnsInternalServerError() Assert.Equal(500, statusCodeResult.StatusCode); Assert.Contains("Unexpected error", statusCodeResult.Value.ToString()); } + + [Fact] + public async Task Login_ValidRequest_ReturnsOk() + { + // Arrange + var userCreditentials = new UserCreditentials { Email = "test@example.com", Password = "Password123" }; + var tokens = new LoginTokens { AccessToken = "valid_token", RefreshToken = "refresh_token" }; + _accountServiceMock.Setup(service => service.LoginAsync(userCreditentials, _userManagerMock.Object, _signInManagerMock.Object)) + .ReturnsAsync(tokens); + + // Act + var result = await _userController.Login(userCreditentials); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(200, okResult.StatusCode); + Assert.Equal(tokens, okResult.Value); + } + [Fact] + public async Task Login_InvalidModelState_ReturnsBadRequest() + { + // Arrange + _userController.ModelState.AddModelError("Email", "The Email field is required."); + var userCreditentials = new UserCreditentials(); + + // Act + var result = await _userController.Login(userCreditentials); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.Equal(400, badRequestResult.StatusCode); + } + + [Fact] + public async Task Refresh_ValidRequest_ReturnsOk() + { + // Arrange + var tokens = new LoginTokens { AccessToken = "valid_token", RefreshToken = "refresh_token" }; + _accountServiceMock.Setup(service => service.RefreshAsync(tokens, _userManagerMock.Object, _tokenServiceMock.Object)) + .ReturnsAsync(tokens); + + // Act + var result = await _userController.Refresh(tokens); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(200, okResult.StatusCode); + Assert.Equal(tokens, okResult.Value); + } + + [Fact] + public async Task GetProfile_UserAuthenticated_ReturnsOk() + { + // Arrange + var userId = "user123"; + var userProfile = new UserProfile { Nickname = "TestUser" }; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _httpContextAccessorMock.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + _accountServiceMock.Setup(service => service.GetUserProfileAsync(_userManagerMock.Object, userId)) + .ReturnsAsync(userProfile); + + // Act + var result = await _userController.GetProfile(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(200, okResult.StatusCode); + Assert.Equal(userProfile, okResult.Value); + } + + [Fact] + public async Task GetProfile_UserDoesNotExist_ReturnsNotFound() + { + // Arrange + var userId = "user123"; + var userProfile = new UserProfile { Nickname = "TestUser" }; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _httpContextAccessorMock.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + _accountServiceMock.Setup(service => service.GetUserProfileAsync(_userManagerMock.Object, userId)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("User from token not found!")); + + // Act + var result = await _userController.GetProfile(); + + // Assert + var statusCodeResult = Assert.IsType(result); + Assert.Equal(404, statusCodeResult.StatusCode); + Assert.Equal("User from token not found!", statusCodeResult.Value); + } + + [Fact] + public async Task EditProfile_ValidRequest_ReturnsOk() + { + // Arrange + var userId = "user123"; + var userProfile = new UserProfile { Nickname = "UpdatedUser" }; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _httpContextAccessorMock.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + _accountServiceMock.Setup(service => service.EditUserProfileAsync(_userManagerMock.Object, userId, userProfile, null)) + .ReturnsAsync(userProfile); + + // Act + var result = await _userController.EditProfile(userProfile, null); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(200, okResult.StatusCode); + Assert.Equal(userProfile, okResult.Value); + } + + [Fact] + public async Task EditProfile_NullUser_ReturnsBadRequest() + { + // Arrange + var userProfile = new UserProfile { Nickname = "UpdatedUser" }; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity()); + _httpContextAccessorMock.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + // Act + var result = await _userController.EditProfile(userProfile, null); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.Equal("No user id provided", badRequestResult.Value); + } + } diff --git a/CollectifyAPI/CollectifyAPI.sln b/CollectifyAPI/CollectifyAPI.sln index c39463e..5daa32d 100644 --- a/CollectifyAPI/CollectifyAPI.sln +++ b/CollectifyAPI/CollectifyAPI.sln @@ -3,9 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35431.28 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI", "CollectifyAPI\CollectifyAPI.csproj", "{6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI.Tests", "CollectifyAPI.test\CollectifyAPI.Tests.csproj", "{3467EC4E-4CB7-4F40-8870-907C40FA7F30}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CollectifyAPI", "CollectifyAPI\CollectifyAPI.csproj", "{6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,10 +15,6 @@ Global {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.Build.0 = Release|Any CPU - {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3467EC4E-4CB7-4F40-8870-907C40FA7F30}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CollectifyAPI/CollectifyAPI/Services/AccountService.cs b/CollectifyAPI/CollectifyAPI/Services/AccountService.cs index c27226d..065e098 100644 --- a/CollectifyAPI/CollectifyAPI/Services/AccountService.cs +++ b/CollectifyAPI/CollectifyAPI/Services/AccountService.cs @@ -18,7 +18,7 @@ public AccountService(TokenService tokenService, IMapper mapper) _mapper = mapper; } - public async Task RegisterAsync(UserCreditentials userCreditentials, UserManager userManager) + public virtual async Task RegisterAsync(UserCreditentials userCreditentials, UserManager userManager) { if (userCreditentials.Email == null) { @@ -53,7 +53,7 @@ public async Task RegisterAsync(UserCreditentials userCreditentials, UserManager } } - public async Task LoginAsync(UserCreditentials userCreditentials, UserManager userManager, SignInManager signInManager) + public virtual async Task LoginAsync(UserCreditentials userCreditentials, UserManager userManager, SignInManager signInManager) { if (userCreditentials.Email == null) { @@ -85,7 +85,7 @@ public async Task LoginAsync(UserCreditentials userCreditentials, U return new LoginTokens(accessToken, refreshToken); } - public async Task RefreshAsync(LoginTokens tokens, UserManager userManager, TokenService tokenService) + public virtual async Task RefreshAsync(LoginTokens tokens, UserManager userManager, TokenService tokenService) { if (tokens.AccessToken == null || tokens.RefreshToken == null) { @@ -116,7 +116,7 @@ public async Task RefreshAsync(LoginTokens tokens, UserManager GetUserProfileAsync(UserManager userManager, string userId) + public virtual async Task GetUserProfileAsync(UserManager userManager, string userId) { var user = await userManager.FindByIdAsync(userId); @@ -128,7 +128,7 @@ public async Task GetUserProfileAsync(UserManager userMana return _mapper.Map(user); } - public async Task EditUserProfileAsync(UserManager userManager, string userId, UserProfile userProfile, IFormFile? avatar) + public virtual async Task EditUserProfileAsync(UserManager userManager, string userId, UserProfile userProfile, IFormFile? avatar) { var user = await userManager.FindByIdAsync(userId); diff --git a/CollectifyAPI/CollectifyAPI/Services/GroupService.cs b/CollectifyAPI/CollectifyAPI/Services/GroupService.cs index b2745b3..8fa49f6 100644 --- a/CollectifyAPI/CollectifyAPI/Services/GroupService.cs +++ b/CollectifyAPI/CollectifyAPI/Services/GroupService.cs @@ -20,7 +20,7 @@ public GroupService(GroupRepository groupRepository, UserManager userMa _mapper = mapper; } - public async Task CreateGroupAsync(Group group, string userId) + public virtual async Task CreateGroupAsync(Group group, string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -36,7 +36,7 @@ public async Task CreateGroupAsync(Group group, string userId) return _mapper.Map(group); } - public async Task UpdateGroupAsync(Group updatedGroup, string userId) + public virtual async Task UpdateGroupAsync(Group updatedGroup, string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -62,7 +62,7 @@ public async Task UpdateGroupAsync(Group updatedGroup, string userI return _mapper.Map(group); } - public async Task DeleteGroupAsync(Guid groupId, string userId) + public virtual async Task DeleteGroupAsync(Guid groupId, string userId) { var group = await _groupRepository.GetByIdAsync(groupId); if (group == null) @@ -84,7 +84,7 @@ public async Task DeleteGroupAsync(Guid groupId, string userId) await _groupRepository.Delete(group); } - public async Task AddMemberToGroupAsync(GroupMember groupMember) + public virtual async Task AddMemberToGroupAsync(GroupMember groupMember) { if (groupMember.MemberId == null || groupMember.GroupId == null) { @@ -106,7 +106,7 @@ public async Task AddMemberToGroupAsync(GroupMember groupMember) await _groupRepository.AddMemberToGroupAsync(groupMember.MemberId, groupMember.GroupId); } - public async Task RemoveMemberFromGroupAsync(GroupMember groupMember) + public virtual async Task RemoveMemberFromGroupAsync(GroupMember groupMember) { if (groupMember.MemberId == null || groupMember.GroupId == null) { @@ -137,7 +137,7 @@ public async Task RemoveMemberFromGroupAsync(GroupMember groupMember) } } - public async Task> GetMembersByGroupIdAsync(Guid groupId) + public virtual async Task> GetMembersByGroupIdAsync(Guid groupId) { var group = await _groupRepository.GetByIdAsync(groupId); if (group == null) @@ -155,7 +155,7 @@ public async Task> GetMembersByGroupIdAsync(Guid groupI }).ToList(); } - public async Task> GetGroupsByCreatorIdAsync(string userId) + public virtual async Task> GetGroupsByCreatorIdAsync(string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -167,7 +167,7 @@ public async Task> GetGroupsByCreatorIdAsync(string use return _mapper.Map>(groups); } - public async Task> GetGroupsByMemberIdAsync(string userId) + public virtual async Task> GetGroupsByMemberIdAsync(string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -180,7 +180,7 @@ public async Task> GetGroupsByMemberIdAsync(string user return _mapper.Map>(groups); } - public async Task GetGroupByIdAsync(Guid groupId, string userId) + public virtual async Task GetGroupByIdAsync(Guid groupId, string userId) { var group = await _groupRepository.GetByIdAsync(groupId); if (group == null) From d4d1f03398ed7ca8e0ffa7cb20b317331782654c Mon Sep 17 00:00:00 2001 From: Pericica Medeea Maria Date: Thu, 30 Jan 2025 16:51:55 +0200 Subject: [PATCH 04/11] tests for groups and notes --- .../ControllersTests/GroupControllerTests.cs | 99 ++++++++- .../ControllersTests/NoteControllerTests.cs | 201 ++++++++++++++++++ 2 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerTests.cs diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs index 4daa418..3ed08ea 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs @@ -172,7 +172,7 @@ public async Task AddMemberToGroup_ValidRequest_ReturnsOk() // Arrange var groupMember = new GroupMember { MemberId = "user123", GroupId = Guid.NewGuid() }; - _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); // Mocking HttpContext + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); _mockGroupService.Setup(service => service.AddMemberToGroupAsync(groupMember)) .Returns(Task.CompletedTask); @@ -212,7 +212,7 @@ public async Task RemoveMemberFromGroup_ValidRequest_ReturnsOk() // Arrange var groupMember = new GroupMember {MemberId = "user123", GroupId = Guid.NewGuid()}; - _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); // Mocking HttpContext + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); _mockGroupService.Setup(service => service.RemoveMemberFromGroupAsync(groupMember)) .Returns(Task.CompletedTask); @@ -248,5 +248,100 @@ public async Task GetGroupById_ValidRequest_ReturnsOk() var returnValue = Assert.IsType(okResult.Value); Assert.Equal(group.Name, returnValue.Name); } + + [Fact] + public async Task GetGroupById_UnauthorizedUser_ReturnsNotFound() + { + // Arrange + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns((HttpContext)null); + var groupId = Guid.NewGuid(); + + // Act + var result = await _groupController.GetGroupById(groupId); + + // Assert + Assert.IsType(result); + } + + + [Fact] + public async Task DeleteGroup_NotTheOwner_ReturnsForbidden() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var groupId = Guid.NewGuid(); + _mockGroupService.Setup(service => service.DeleteGroupAsync(groupId, userId)) + .ThrowsAsync(new ActionResponseExceptions.ForbiddenAccessException("You are not the owner of this group!")); + + // Act + var result = await _groupController.DeleteGroup(groupId); + + // Assert + var objectResult = Assert.IsType(result); + Assert.Equal(403, objectResult.StatusCode); + } + + [Fact] + public async Task AddMemberToGroup_GroupNotFound_ReturnsNotFound() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var groupMember = new GroupMember { MemberId = "user456", GroupId = Guid.NewGuid() }; + _mockGroupService.Setup(service => service.AddMemberToGroupAsync(groupMember)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("Group not found!")); + + // Act + var result = await _groupController.AddMemberToGroup(groupMember); + + // Assert + var objectResult = Assert.IsType(result); + Assert.Equal(404, objectResult.StatusCode); + } + + [Fact] + public async Task RemoveMemberFromGroup_UnauthorizedUser_ReturnsNotFound() + { + // Arrange + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns((HttpContext)null); // No user authenticated + var groupMember = new GroupMember { MemberId = "user456", GroupId = Guid.NewGuid() }; + + // Act + var result = await _groupController.RemoveMemberFromGroup(groupMember); + + // Assert + Assert.IsType(result); // Update to match the actual result type + } + + [Fact] + public async Task GetGroupsByMemberId_ValidRequest_ReturnsOk() + { + // Arrange + var userId = "user123"; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) })); + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + + var groups = new List + { + new SimpleGroup { Id = Guid.NewGuid(), Name = "Group 1" }, + new SimpleGroup { Id = Guid.NewGuid(), Name = "Group 2" } + }; + + _mockGroupService.Setup(service => service.GetGroupsByMemberIdAsync(userId)).ReturnsAsync(groups); + + // Act + var result = await _groupController.GetGroupsByMemberId(); + + // Assert + var okResult = Assert.IsType(result); + Assert.IsType>(okResult.Value); + } + } + } diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerTests.cs new file mode 100644 index 0000000..1b9a1d4 --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerTests.cs @@ -0,0 +1,201 @@ +using Moq; +using Xunit; +using Microsoft.AspNetCore.Mvc; +using CollectifyAPI.Controllers; +using CollectifyAPI.Services; +using CollectifyAPI.Dtos; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using System.Security.Claims; +using System; +using System.Collections.Generic; +using CollectifyAPI.Helpers; +using CollectifyAPI.Data; + +namespace CollectifyAPI.Tests +{ + public class NoteControllerTests + { + private readonly Mock _mockNoteService; + private readonly Mock _mockHttpContextAccessor; + private readonly NoteController _noteController; + + public NoteControllerTests() + { + _mockNoteService = new Mock(MockBehavior.Strict, null, null, null, null); + _mockHttpContextAccessor = new Mock(); + _noteController = new NoteController(_mockNoteService.Object, _mockHttpContextAccessor.Object); + } + + private void SetUpHttpContext(string? userId) + { + var claims = userId != null ? new[] { new Claim(ClaimTypes.NameIdentifier, userId) } : new Claim[] { }; + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims)); + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns(new DefaultHttpContext { User = claimsPrincipal }); + } + + // ✅ Positive Tests + [Fact] + public async Task GetOwnedNotes_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + _mockNoteService.Setup(service => service.GetOwnedNotesAsync(userId)).ReturnsAsync(new List()); + + var result = await _noteController.GetOwnedNotes(); + + var okResult = Assert.IsType(result); + Assert.IsType>(okResult.Value); + } + + [Fact] + public async Task CreateNote_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + var newNote = new SimpleNote { Id = Guid.NewGuid(), Title = "Test Note", Content = "Test Content" }; + _mockNoteService.Setup(service => service.CreateNoteAsync(userId, newNote)).ReturnsAsync(newNote); + + var result = await _noteController.CreateNote(newNote); + + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(newNote.Title, returnValue.Title); + } + + [Fact] + public async Task UpdateNote_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + var updatedNote = new SimpleNote { Id = Guid.NewGuid(), Title = "Updated Note", Content = "Updated Content" }; + _mockNoteService.Setup(service => service.UpdateNoteAsync(userId, updatedNote)).ReturnsAsync(updatedNote); + + var result = await _noteController.UpdateNote(updatedNote); + + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(updatedNote.Title, returnValue.Title); + } + + [Fact] + public async Task DeleteNote_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + var noteId = Guid.NewGuid(); + _mockNoteService.Setup(service => service.DeleteNoteAsync(userId, noteId)).Returns(Task.CompletedTask); + + var result = await _noteController.DeleteNote(noteId); + + Assert.IsType(result); + } + + [Fact] + public async Task GetNote_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + var noteId = Guid.NewGuid(); + var note = new SimpleNote { Id = noteId, Title = "Test Note", Content = "Test Content" }; + _mockNoteService.Setup(service => service.GetNoteAsync(noteId, userId)).ReturnsAsync(note); + + var result = await _noteController.GetNote(noteId); + + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(note.Title, returnValue.Title); + } + + [Fact] + public async Task GetNotesFromGroup_ValidRequest_ReturnsOk() + { + var userId = "user123"; + SetUpHttpContext(userId); + var groupId = Guid.NewGuid(); + var notes = new List { new SimpleNote { Id = Guid.NewGuid(), Title = "Group Note", Content = "Group Content" } }; + _mockNoteService.Setup(service => service.GetNotesByGroupIdAsync(groupId)).ReturnsAsync(notes); + + var result = await _noteController.GetNotesFromGroup(groupId); + + var okResult = Assert.IsType(result); + Assert.IsType>(okResult.Value); + } + + // ❌ Negative Tests + + [Fact] + public async Task CreateNote_UnauthorizedUser_ReturnsBadRequest() + { + SetUpHttpContext(null); // No user authenticated + + var result = await _noteController.CreateNote(new SimpleNote()); + + Assert.IsType(result); + } + + [Fact] + public async Task UpdateNote_UserNotOwner_ReturnsForbidden() + { + var userId = "user123"; + SetUpHttpContext(userId); + var updatedNote = new SimpleNote { Id = Guid.NewGuid(), Title = "Updated Note" }; + + _mockNoteService.Setup(service => service.UpdateNoteAsync(userId, updatedNote)) + .ThrowsAsync(new ActionResponseExceptions.ForbiddenAccessException("You can't update this note!")); + + var result = await _noteController.UpdateNote(updatedNote); + + var objectResult = Assert.IsType(result); + Assert.Equal(403, objectResult.StatusCode); + } + + [Fact] + public async Task DeleteNote_NoteNotFound_ReturnsNotFound() + { + var userId = "user123"; + SetUpHttpContext(userId); + var noteId = Guid.NewGuid(); + + _mockNoteService.Setup(service => service.DeleteNoteAsync(userId, noteId)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("Note not found!")); + + var result = await _noteController.DeleteNote(noteId); + + var objectResult = Assert.IsType(result); + Assert.Equal(404, objectResult.StatusCode); + } + + [Fact] + public async Task GetNote_NoteNotFound_ReturnsNotFound() + { + var userId = "user123"; + SetUpHttpContext(userId); + var noteId = Guid.NewGuid(); + + _mockNoteService.Setup(service => service.GetNoteAsync(noteId, userId)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("Note not found!")); + + var result = await _noteController.GetNote(noteId); + + var objectResult = Assert.IsType(result); + Assert.Equal(404, objectResult.StatusCode); + } + + [Fact] + public async Task GetNotesFromGroup_GroupNotFound_ReturnsNotFound() + { + var userId = "user123"; + SetUpHttpContext(userId); + var groupId = Guid.NewGuid(); + + _mockNoteService.Setup(service => service.GetNotesByGroupIdAsync(groupId)) + .ThrowsAsync(new ActionResponseExceptions.NotFoundException("Group not found!")); + + var result = await _noteController.GetNotesFromGroup(groupId); + + var objectResult = Assert.IsType(result); + Assert.Equal(404, objectResult.StatusCode); + } + } +} From bf53df8e6dfb4caee8ef9c7a92512944b5825bcc Mon Sep 17 00:00:00 2001 From: Pericica Medeea Maria Date: Fri, 31 Jan 2025 15:59:13 +0200 Subject: [PATCH 05/11] integration tests --- .../CollectifyAPI.Tests.csproj | 25 +++- .../ControllersTests/GroupControllerTests.cs | 4 +- .../IntegrationTestFactory.cs | 35 ++++++ .../NoteControllerIntegrationTests.cs | 115 ++++++++++++++++++ 4 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs create mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs diff --git a/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj index 7317f9e..d8e6ea2 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj +++ b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj @@ -4,17 +4,26 @@ net8.0 enable enable - + bin\Debug\net8.0\ false true + true - - + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + @@ -25,4 +34,10 @@ + + + PreserveNewest + + + diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs index 3ed08ea..cf9fbfd 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/GroupControllerTests.cs @@ -308,14 +308,14 @@ public async Task AddMemberToGroup_GroupNotFound_ReturnsNotFound() public async Task RemoveMemberFromGroup_UnauthorizedUser_ReturnsNotFound() { // Arrange - _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns((HttpContext)null); // No user authenticated + _mockHttpContextAccessor.Setup(h => h.HttpContext).Returns((HttpContext)null); var groupMember = new GroupMember { MemberId = "user456", GroupId = Guid.NewGuid() }; // Act var result = await _groupController.RemoveMemberFromGroup(groupMember); // Assert - Assert.IsType(result); // Update to match the actual result type + Assert.IsType(result); } [Fact] diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs new file mode 100644 index 0000000..897b60e --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using CollectifyAPI.Data; +using Microsoft.VisualStudio.TestPlatform.TestHost; +using System; + +public class IntegrationTestFactory : WebApplicationFactory +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + // Remove existing database configuration + var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); + if (descriptor != null) services.Remove(descriptor); + + // Add an in-memory database for testing + services.AddDbContext(options => + options.UseInMemoryDatabase("TestDb")); + + // Rebuild the service provider + var provider = services.BuildServiceProvider(); + + // Initialize the database + using (var scope = provider.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.Database.EnsureDeleted(); + dbContext.Database.EnsureCreated(); + } + }); + } +} diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs new file mode 100644 index 0000000..f7739ae --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs @@ -0,0 +1,115 @@ +using System.Net; +using System.Net.Http.Json; +using System.Text; +using CollectifyAPI.Dtos; +using CollectifyAPI.Models; +using Newtonsoft.Json; +using Xunit; + +public class NoteControllerIntegrationTests : IClassFixture +{ + private readonly HttpClient _client; + + public NoteControllerIntegrationTests(IntegrationTestFactory factory) + { + _client = factory.CreateClient(); + } + + private async Task AuthenticateAsync() + { + var credentials = new { Email = "testuser@example.com", Password = "Password123!" }; + var registerResponse = await _client.PostAsJsonAsync("/api/account/register", credentials); + if (registerResponse.StatusCode != HttpStatusCode.OK) return string.Empty; + + var loginResponse = await _client.PostAsJsonAsync("/api/account/login", credentials); + var loginContent = await loginResponse.Content.ReadAsStringAsync(); + var loginResult = JsonConvert.DeserializeObject(loginContent); + + return loginResult?.AccessToken ?? string.Empty; + } + + [Fact] + public async Task CreateNote_ValidRequest_ReturnsCreatedNote() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + var newNote = new SimpleNote { Title = "Integration Test Note", Content = "Test Content" }; + var response = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); + + response.EnsureSuccessStatusCode(); + var createdNote = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(createdNote); + Assert.Equal("Integration Test Note", createdNote.Title); + } + + [Fact] + public async Task GetNote_ValidId_ReturnsNote() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + var newNote = new SimpleNote { Title = "Integration Test Note", Content = "Test Content" }; + var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); + var createdNote = await createResponse.Content.ReadFromJsonAsync(); + + var response = await _client.GetAsync($"/api/notes/get_note?noteId={createdNote.Id}"); + response.EnsureSuccessStatusCode(); + var retrievedNote = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(retrievedNote); + Assert.Equal(createdNote.Title, retrievedNote.Title); + } + + [Fact] + public async Task UpdateNote_ValidRequest_ReturnsUpdatedNote() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + var newNote = new SimpleNote { Title = "Old Title", Content = "Old Content" }; + var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); + var createdNote = await createResponse.Content.ReadFromJsonAsync(); + + var updatedNote = new SimpleNote { Id = createdNote.Id, Title = "Updated Title", Content = "Updated Content" }; + var updateResponse = await _client.PutAsJsonAsync("/api/notes/update_note", updatedNote); + + updateResponse.EnsureSuccessStatusCode(); + var returnedNote = await updateResponse.Content.ReadFromJsonAsync(); + + Assert.Equal("Updated Title", returnedNote.Title); + } + + [Fact] + public async Task DeleteNote_ValidId_ReturnsOk() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + var newNote = new SimpleNote { Title = "Delete Me", Content = "Test Content" }; + var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); + var createdNote = await createResponse.Content.ReadFromJsonAsync(); + + var deleteResponse = await _client.DeleteAsync($"/api/notes/delete_note?noteId={createdNote.Id}"); + + Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode); + } + + [Fact] + public async Task GetOwnedNotes_ReturnsNotes() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + await _client.PostAsJsonAsync("/api/notes/add_note", new SimpleNote { Title = "Test Note 1", Content = "Content 1" }); + await _client.PostAsJsonAsync("/api/notes/add_note", new SimpleNote { Title = "Test Note 2", Content = "Content 2" }); + + var response = await _client.GetAsync("/api/notes/owned_notes"); + response.EnsureSuccessStatusCode(); + var notes = await response.Content.ReadFromJsonAsync>(); + + Assert.NotEmpty(notes); + Assert.True(notes.Count >= 2); + } +} From 44f38f35d5ca2bf34d07222399e2a323ff2f5790 Mon Sep 17 00:00:00 2001 From: Pericica Medeea Maria Date: Fri, 31 Jan 2025 21:44:39 +0200 Subject: [PATCH 06/11] integration tests for notes and groups --- .../CollectifyAPI.Tests.csproj | 2 +- .../IntegrationTestFactory.cs | 35 ----- .../GroupControllerIntegrationTests .cs | 135 ++++++++++++++++++ .../IntegrationTestFactory.cs | 78 ++++++++++ .../NoteControllerIntegrationTests .cs} | 75 ++++------ CollectifyAPI/CollectifyAPI.sln | 8 +- .../CollectifyAPI/CollectifyAPI.csproj | 2 +- CollectifyAPI/CollectifyAPI/Program.cs | 2 + .../CollectifyAPI/Services/NoteService.cs | 12 +- 9 files changed, 260 insertions(+), 89 deletions(-) delete mode 100644 CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs create mode 100644 CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/GroupControllerIntegrationTests .cs create mode 100644 CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/IntegrationTestFactory.cs rename CollectifyAPI/CollectifyAPI.Tests/{ControllersTests/NoteControllerIntegrationTests.cs => IntegrationTests/NoteControllerIntegrationTests .cs} (54%) diff --git a/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj index d8e6ea2..2a285c4 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj +++ b/CollectifyAPI/CollectifyAPI.Tests/CollectifyAPI.Tests.csproj @@ -16,7 +16,7 @@ all - + diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs b/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs deleted file mode 100644 index 897b60e..0000000 --- a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/IntegrationTestFactory.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using CollectifyAPI.Data; -using Microsoft.VisualStudio.TestPlatform.TestHost; -using System; - -public class IntegrationTestFactory : WebApplicationFactory -{ - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.ConfigureServices(services => - { - // Remove existing database configuration - var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); - if (descriptor != null) services.Remove(descriptor); - - // Add an in-memory database for testing - services.AddDbContext(options => - options.UseInMemoryDatabase("TestDb")); - - // Rebuild the service provider - var provider = services.BuildServiceProvider(); - - // Initialize the database - using (var scope = provider.CreateScope()) - { - var dbContext = scope.ServiceProvider.GetRequiredService(); - dbContext.Database.EnsureDeleted(); - dbContext.Database.EnsureCreated(); - } - }); - } -} diff --git a/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/GroupControllerIntegrationTests .cs b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/GroupControllerIntegrationTests .cs new file mode 100644 index 0000000..faddf29 --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/GroupControllerIntegrationTests .cs @@ -0,0 +1,135 @@ +using System.Net; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using CollectifyAPI.Dtos; +using CollectifyAPI.Models; +using Newtonsoft.Json; +using Xunit; + +public class GroupControllerIntegrationTests : IClassFixture +{ + private readonly HttpClient _client; + + public GroupControllerIntegrationTests(IntegrationTestFactory factory) + { + _client = factory.CreateClient(); + } + + private async Task AuthenticateAsync() + { + var email = $"testuser-{Guid.NewGuid()}@example.com"; + var credentials = new { Email = email, Password = "Password123!" }; + + // Attempt to register the user + var registerResponse = await _client.PostAsJsonAsync("/api/account/register", credentials); + if (registerResponse.StatusCode != HttpStatusCode.OK && registerResponse.StatusCode != HttpStatusCode.BadRequest) + { + var error = await registerResponse.Content.ReadAsStringAsync(); + throw new Exception($"Registration failed: {error}"); + } + + // Login to get the token + var loginResponse = await _client.PostAsJsonAsync("/api/account/login", credentials); + if (!loginResponse.IsSuccessStatusCode) + { + var error = await loginResponse.Content.ReadAsStringAsync(); + throw new Exception($"Login failed: {error}"); + } + + var loginContent = await loginResponse.Content.ReadAsStringAsync(); + var loginResult = JsonConvert.DeserializeObject(loginContent); + + return loginResult?.AccessToken ?? throw new Exception("Token generation failed"); + } + + [Fact] + public async Task GetGroupById_ValidRequest_ReturnsGroup() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // Create a group + var newGroup = new Group { Name = "Integration Test Group" }; + var createResponse = await _client.PostAsJsonAsync("/api/groups/create_group", newGroup); + var createdGroup = await createResponse.Content.ReadFromJsonAsync(); + + // Retrieve the group by ID + var response = await _client.GetAsync($"/api/groups/get_group?groupId={createdGroup.Id}"); + response.EnsureSuccessStatusCode(); + var retrievedGroup = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(retrievedGroup); + Assert.Equal(createdGroup.Name, retrievedGroup.Name); + } + + [Fact] + public async Task UpdateGroup_ValidRequest_ReturnsUpdatedGroup() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // Create a group + var newGroup = new Group { Name = "Old Group Name" }; + var createResponse = await _client.PostAsJsonAsync("/api/groups/create_group", newGroup); + createResponse.EnsureSuccessStatusCode(); + + var createdGroup = await createResponse.Content.ReadFromJsonAsync(); + Assert.NotNull(createdGroup); // Ensure the object is not null + + // Update the group + var updatedGroup = new Group + { + Id = (Guid)createdGroup!.Id, // Safe to access after Assert.NotNull + Name = "Updated Group Name" + }; + + var updateResponse = await _client.PutAsJsonAsync("/api/groups/update_group", updatedGroup); + updateResponse.EnsureSuccessStatusCode(); + + var updated = await updateResponse.Content.ReadFromJsonAsync(); + Assert.NotNull(updated); + Assert.Equal("Updated Group Name", updated!.Name); + } + + + [Fact] + public async Task DeleteGroup_ValidRequest_ReturnsOk() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + var uniqueGroupName = $"TestGroup-{Guid.NewGuid()}"; + var newGroup = new Group { Name = uniqueGroupName }; + var createResponse = await _client.PostAsJsonAsync("/api/groups/create_group", newGroup); + createResponse.EnsureSuccessStatusCode(); + + var createdGroup = await createResponse.Content.ReadFromJsonAsync(); + Assert.NotNull(createdGroup); + + var deleteResponse = await _client.DeleteAsync($"/api/groups/delete_group?groupId={createdGroup!.Id}"); + Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode); + } + + + [Fact] + public async Task AddMemberToGroup_ValidRequest_ReturnsOk() + { + var token = await AuthenticateAsync(); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // Create a group + var newGroup = new Group { Name = "Group for Member Addition" }; + var createResponse = await _client.PostAsJsonAsync("/api/groups/create_group", newGroup); + createResponse.EnsureSuccessStatusCode(); + + var createdGroup = await createResponse.Content.ReadFromJsonAsync(); + Assert.NotNull(createdGroup); + + // Add a member to the group + var member = new GroupMember { MemberId = "testUserId", GroupId = createdGroup!.Id }; + var response = await _client.PostAsJsonAsync("/api/groups/add_member", member); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + +} diff --git a/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/IntegrationTestFactory.cs b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/IntegrationTestFactory.cs new file mode 100644 index 0000000..cefa9ee --- /dev/null +++ b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/IntegrationTestFactory.cs @@ -0,0 +1,78 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using CollectifyAPI.Data; +using CollectifyAPI.Models; +using System; +using System.Linq; + +public class IntegrationTestFactory : WebApplicationFactory +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + // Remove existing database configuration + var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); + if (descriptor != null) + { + services.Remove(descriptor); + } + + // Add an in-memory database for testing + services.AddDbContext(options => + options.UseInMemoryDatabase("TestDb")); + + // Rebuild the service provider + var provider = services.BuildServiceProvider(); + + // Initialize the database + using (var scope = provider.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.Database.EnsureDeleted(); + dbContext.Database.EnsureCreated(); + + // Seed initial data + SeedTestData(dbContext); + } + }); + } + + private void SeedTestData(ApplicationDbContext dbContext) + { + // Add test users, avoiding duplicates + if (!dbContext.Users.Any(u => u.Id == "testUserId")) + { + dbContext.Users.Add(new AppUser + { + Id = "testUserId", + Email = "testuser@example.com", + UserName = "testuser@example.com" + }); + } + + if (!dbContext.Users.Any(u => u.Id == "testUserId2")) + { + dbContext.Users.Add(new AppUser + { + Id = "testUserId2", + Email = "testuser2@example.com", + UserName = "testuser2@example.com" + }); + } + if (!dbContext.Users.Any(u => u.Id == "testUserId3")) + { + dbContext.Users.Add(new AppUser + { + Id = "testUserId3", + Email = "testuser3@example.com", + UserName = "testuser3@example.com" + }); + } + + dbContext.SaveChanges(); + } + +} diff --git a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/NoteControllerIntegrationTests .cs similarity index 54% rename from CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs rename to CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/NoteControllerIntegrationTests .cs index f7739ae..3fe3d5e 100644 --- a/CollectifyAPI/CollectifyAPI.Tests/ControllersTests/NoteControllerIntegrationTests.cs +++ b/CollectifyAPI/CollectifyAPI.Tests/IntegrationTests/NoteControllerIntegrationTests .cs @@ -1,6 +1,6 @@ using System.Net; +using System.Net.Http.Headers; using System.Net.Http.Json; -using System.Text; using CollectifyAPI.Dtos; using CollectifyAPI.Models; using Newtonsoft.Json; @@ -17,56 +17,38 @@ public NoteControllerIntegrationTests(IntegrationTestFactory factory) private async Task AuthenticateAsync() { - var credentials = new { Email = "testuser@example.com", Password = "Password123!" }; - var registerResponse = await _client.PostAsJsonAsync("/api/account/register", credentials); - if (registerResponse.StatusCode != HttpStatusCode.OK) return string.Empty; - - var loginResponse = await _client.PostAsJsonAsync("/api/account/login", credentials); - var loginContent = await loginResponse.Content.ReadAsStringAsync(); - var loginResult = JsonConvert.DeserializeObject(loginContent); - return loginResult?.AccessToken ?? string.Empty; - } + var email = $"testuser-{Guid.NewGuid()}@example.com"; + var credentials = new { Email = email, Password = "Password123!" }; - [Fact] - public async Task CreateNote_ValidRequest_ReturnsCreatedNote() - { - var token = await AuthenticateAsync(); - _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - - var newNote = new SimpleNote { Title = "Integration Test Note", Content = "Test Content" }; - var response = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); - - response.EnsureSuccessStatusCode(); - var createdNote = await response.Content.ReadFromJsonAsync(); - - Assert.NotNull(createdNote); - Assert.Equal("Integration Test Note", createdNote.Title); - } - [Fact] - public async Task GetNote_ValidId_ReturnsNote() - { - var token = await AuthenticateAsync(); - _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + // Attempt to register the user + var registerResponse = await _client.PostAsJsonAsync("/api/account/register", credentials); + if (!registerResponse.IsSuccessStatusCode && registerResponse.StatusCode != HttpStatusCode.BadRequest) + { + var error = await registerResponse.Content.ReadAsStringAsync(); + throw new Exception($"Registration failed: {error}"); + } - var newNote = new SimpleNote { Title = "Integration Test Note", Content = "Test Content" }; - var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); - var createdNote = await createResponse.Content.ReadFromJsonAsync(); + // Login to get the token + var loginResponse = await _client.PostAsJsonAsync("/api/account/login", credentials); + if (!loginResponse.IsSuccessStatusCode) + { + var error = await loginResponse.Content.ReadAsStringAsync(); + throw new Exception($"Login failed: {error}"); + } - var response = await _client.GetAsync($"/api/notes/get_note?noteId={createdNote.Id}"); - response.EnsureSuccessStatusCode(); - var retrievedNote = await response.Content.ReadFromJsonAsync(); + var loginContent = await loginResponse.Content.ReadAsStringAsync(); + var loginResult = JsonConvert.DeserializeObject(loginContent); - Assert.NotNull(retrievedNote); - Assert.Equal(createdNote.Title, retrievedNote.Title); + return loginResult?.AccessToken ?? throw new Exception("Token generation failed"); } [Fact] public async Task UpdateNote_ValidRequest_ReturnsUpdatedNote() { var token = await AuthenticateAsync(); - _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var newNote = new SimpleNote { Title = "Old Title", Content = "Old Content" }; var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); @@ -82,25 +64,28 @@ public async Task UpdateNote_ValidRequest_ReturnsUpdatedNote() } [Fact] - public async Task DeleteNote_ValidId_ReturnsOk() + public async Task DeleteNote_ValidRequest_ReturnsOk() { var token = await AuthenticateAsync(); - _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - var newNote = new SimpleNote { Title = "Delete Me", Content = "Test Content" }; + var newNote = new SimpleNote { Title = "Test Note", Content = "Test Content" }; var createResponse = await _client.PostAsJsonAsync("/api/notes/add_note", newNote); - var createdNote = await createResponse.Content.ReadFromJsonAsync(); + createResponse.EnsureSuccessStatusCode(); - var deleteResponse = await _client.DeleteAsync($"/api/notes/delete_note?noteId={createdNote.Id}"); + var createdNote = await createResponse.Content.ReadFromJsonAsync(); + Assert.NotNull(createdNote); + var deleteResponse = await _client.DeleteAsync($"/api/notes/delete_note?noteId={createdNote!.Id}"); Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode); } + [Fact] public async Task GetOwnedNotes_ReturnsNotes() { var token = await AuthenticateAsync(); - _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); await _client.PostAsJsonAsync("/api/notes/add_note", new SimpleNote { Title = "Test Note 1", Content = "Content 1" }); await _client.PostAsJsonAsync("/api/notes/add_note", new SimpleNote { Title = "Test Note 2", Content = "Content 2" }); diff --git a/CollectifyAPI/CollectifyAPI.sln b/CollectifyAPI/CollectifyAPI.sln index 5daa32d..33ed12b 100644 --- a/CollectifyAPI/CollectifyAPI.sln +++ b/CollectifyAPI/CollectifyAPI.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35431.28 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CollectifyAPI", "CollectifyAPI\CollectifyAPI.csproj", "{6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI", "CollectifyAPI\CollectifyAPI.csproj", "{6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectifyAPI.Tests", "CollectifyAPI.Tests\CollectifyAPI.Tests.csproj", "{1440ABED-5611-4906-B8FC-E275401B8D41}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EC59B5D-5CDC-4922-A652-1AC4E1B9AF88}.Release|Any CPU.Build.0 = Release|Any CPU + {1440ABED-5611-4906-B8FC-E275401B8D41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1440ABED-5611-4906-B8FC-E275401B8D41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1440ABED-5611-4906-B8FC-E275401B8D41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1440ABED-5611-4906-B8FC-E275401B8D41}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CollectifyAPI/CollectifyAPI/CollectifyAPI.csproj b/CollectifyAPI/CollectifyAPI/CollectifyAPI.csproj index ea5e499..e186981 100644 --- a/CollectifyAPI/CollectifyAPI/CollectifyAPI.csproj +++ b/CollectifyAPI/CollectifyAPI/CollectifyAPI.csproj @@ -11,7 +11,7 @@ - + all diff --git a/CollectifyAPI/CollectifyAPI/Program.cs b/CollectifyAPI/CollectifyAPI/Program.cs index 4a22f93..8eceafd 100644 --- a/CollectifyAPI/CollectifyAPI/Program.cs +++ b/CollectifyAPI/CollectifyAPI/Program.cs @@ -69,3 +69,5 @@ app.MapControllers(); app.Run(); + +public partial class Program { } \ No newline at end of file diff --git a/CollectifyAPI/CollectifyAPI/Services/NoteService.cs b/CollectifyAPI/CollectifyAPI/Services/NoteService.cs index 3bca938..9a670ca 100644 --- a/CollectifyAPI/CollectifyAPI/Services/NoteService.cs +++ b/CollectifyAPI/CollectifyAPI/Services/NoteService.cs @@ -23,7 +23,7 @@ public NoteService(NoteRepository noteRepository, GroupRepository groupRepositor _mapper = mapper; } - public async Task CreateNoteAsync(string userId, SimpleNote note) + public virtual async Task CreateNoteAsync(string userId, SimpleNote note) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -51,7 +51,7 @@ public async Task CreateNoteAsync(string userId, SimpleNote note) return _mapper.Map(newNote); } - public async Task> GetOwnedNotesAsync(string userId) + public virtual async Task> GetOwnedNotesAsync(string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -75,7 +75,7 @@ public async Task> GetOwnedNotesAsync(string userId) return await Task.WhenAll(decryptedNotesTasks); } - public async Task UpdateNoteAsync(string userId, SimpleNote updatedNote) + public virtual async Task UpdateNoteAsync(string userId, SimpleNote updatedNote) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -108,7 +108,7 @@ public async Task UpdateNoteAsync(string userId, SimpleNote updatedN return updatedNote; } - public async Task DeleteNoteAsync(string userId, Guid id) + public virtual async Task DeleteNoteAsync(string userId, Guid id) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -130,7 +130,7 @@ public async Task DeleteNoteAsync(string userId, Guid id) await _noteRepository.Delete(note); } - public async Task GetNoteAsync(Guid id, string userId) + public virtual async Task GetNoteAsync(Guid id, string userId) { var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -152,7 +152,7 @@ public async Task GetNoteAsync(Guid id, string userId) return simpleNote; } - public async Task> GetNotesByGroupIdAsync(Guid groupId) + public virtual async Task> GetNotesByGroupIdAsync(Guid groupId) { var group = await _groupRepository.GetByIdAsync(groupId); if (group == null) From 346f7c61cea79cb13fc92256cdfa3dac0abc97b5 Mon Sep 17 00:00:00 2001 From: BiancaDogareci Date: Sat, 1 Feb 2025 15:56:21 +0200 Subject: [PATCH 07/11] added link to different api endpoint in a comment, fixed empy notes/spaces lists, other small changes --- CollectifyFrontend/app/(tabs)/groups.tsx | 9 +++++---- CollectifyFrontend/app/(tabs)/index.tsx | 13 ++++++++++++- CollectifyFrontend/app/_layout.tsx | 7 +++++++ CollectifyFrontend/app/login.tsx | 2 +- CollectifyFrontend/app/profile.tsx | 2 +- CollectifyFrontend/services/axiosInstance.ts | 2 +- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CollectifyFrontend/app/(tabs)/groups.tsx b/CollectifyFrontend/app/(tabs)/groups.tsx index 8b59867..d646b82 100644 --- a/CollectifyFrontend/app/(tabs)/groups.tsx +++ b/CollectifyFrontend/app/(tabs)/groups.tsx @@ -99,7 +99,9 @@ export default function GroupsScreen() { {groups.length > 0 ? ( ) : ( - No groups available. Add a new group! + + No spaces available. Create one! + )}