Added tests, need to go through them manually to check if they make sense and are correct later
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using FluentAssertions;
|
||||
using Lutra.API.IntegrationTests.Infrastructure;
|
||||
using Lutra.Application.Supermarkten;
|
||||
using Lutra.Domain.Entities;
|
||||
|
||||
namespace Lutra.API.IntegrationTests.Controllers;
|
||||
|
||||
public class SupermarktenControllerTests(LutraApiFactory factory)
|
||||
: IntegrationTestBase(factory)
|
||||
{
|
||||
// ── GET /api/supermarkten ─────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsOk_WithEmptyList_WhenNoDataExists()
|
||||
{
|
||||
var response = await Client.GetAsync("/api/supermarkten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body.Should().NotBeNull();
|
||||
body!.Supermarkten.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsSeededSupermarkt()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Albert Heijn",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body!.Supermarkten.Should().HaveCount(1);
|
||||
body.Supermarkten.First().Naam.Should().Be("Albert Heijn");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsAllSeededSupermarkten()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Albert Heijn",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Jumbo",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Picnic",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body!.Supermarkten.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
// ── GET /api/supermarkten — pagination ────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_Pagination_ReturnsCorrectPage()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Albert Heijn",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Jumbo",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Picnic",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten?skip=1&take=1");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body!.Supermarkten.Should().HaveCount(1);
|
||||
// Handler orders by Naam ascending, so skip=1 skips "Albert Heijn" and returns "Jumbo".
|
||||
body.Supermarkten.First().Naam.Should().Be("Jumbo");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_Pagination_ReturnsEmptyList_WhenSkipExceedsTotalCount()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Albert Heijn",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten?skip=10&take=50");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body!.Supermarkten.Should().BeEmpty();
|
||||
}
|
||||
|
||||
// ── GET /api/supermarkten — sorting ───────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsSupermarkten_OrderedByNaamAscending()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Picnic",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Albert Heijn",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
var namen = body!.Supermarkten.Select(s => s.Naam).ToList();
|
||||
namen.Should().BeInAscendingOrder();
|
||||
}
|
||||
|
||||
// ── Soft-delete behaviour ─────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_DoesNotReturn_SoftDeletedSupermarkt()
|
||||
{
|
||||
await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Verwijderd",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow,
|
||||
DeletedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/supermarkten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetSupermarkten.Response>();
|
||||
body!.Supermarkten.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using FluentAssertions;
|
||||
using Lutra.API.IntegrationTests.Infrastructure;
|
||||
using Lutra.API.Requests;
|
||||
using Lutra.Application.Verspakketten;
|
||||
using Lutra.Domain.Entities;
|
||||
|
||||
namespace Lutra.API.IntegrationTests.Controllers;
|
||||
|
||||
public class VerspakkettenControllerTests(LutraApiFactory factory)
|
||||
: IntegrationTestBase(factory)
|
||||
{
|
||||
// ── GET /api/verspakketten ────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsOk_WithEmptyList_WhenNoDataExists()
|
||||
{
|
||||
var response = await Client.GetAsync("/api/verspakketten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetVerspakketten.Response>();
|
||||
body.Should().NotBeNull();
|
||||
body!.Verspakketten.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_ReturnsSeededVerspakket()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Lente Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/verspakketten");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetVerspakketten.Response>();
|
||||
body!.Verspakketten.Should().HaveCount(1);
|
||||
body.Verspakketten.First().Naam.Should().Be("Lente Pakket");
|
||||
}
|
||||
|
||||
// ── GET /api/verspakketten/{id} ───────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task GetById_ReturnsNotFound_WhenVerspakketDoesNotExist()
|
||||
{
|
||||
var response = await Client.GetAsync($"/api/verspakketten/{Guid.NewGuid()}");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetById_ReturnsVerspakket_WhenItExists()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Jumbo",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
var verspakket = await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Zomer Pakket", AantalPersonen = 4,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync($"/api/verspakketten/{verspakket.Id}");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetVerspakket.Response>();
|
||||
body!.Verspakket.Should().NotBeNull();
|
||||
body.Verspakket!.Naam.Should().Be("Zomer Pakket");
|
||||
}
|
||||
|
||||
// ── POST /api/verspakketten ───────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Post_CreatesVerspakket_AndReturns201()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Picnic",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var command = new CreateVerspakket.Command("Herfst Pakket", 1499, 3, supermarkt.Id);
|
||||
var response = await Client.PostAsJsonAsync("/api/verspakketten", command);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
||||
var body = await response.Content.ReadFromJsonAsync<CreateVerspakket.Response>();
|
||||
body!.Id.Should().NotBeEmpty();
|
||||
response.Headers.Location.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Post_ReturnsBadRequest_WhenSupermarktDoesNotExist()
|
||||
{
|
||||
var command = new CreateVerspakket.Command("Winter Pakket", 999, 2, Guid.NewGuid());
|
||||
var response = await Client.PostAsJsonAsync("/api/verspakketten", command);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
// ── PUT /api/verspakketten/{id} ───────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Update_ReturnsNoContent_WhenVerspakketExists()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
var verspakket = await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Oud Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var request = new UpdateVerspakketRequest("Nieuw Pakket", 1999, 3, supermarkt.Id);
|
||||
var response = await Client.PutAsJsonAsync($"/api/verspakketten/{verspakket.Id}", request);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NoContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Update_ReturnsNotFound_WhenVerspakketDoesNotExist()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var request = new UpdateVerspakketRequest("Pakket", 999, 2, supermarkt.Id);
|
||||
var response = await Client.PutAsJsonAsync($"/api/verspakketten/{Guid.NewGuid()}", request);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Update_ReturnsBadRequest_WhenSupermarktDoesNotExist()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
var verspakket = await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var request = new UpdateVerspakketRequest("Pakket", 999, 2, Guid.NewGuid());
|
||||
var response = await Client.PutAsJsonAsync($"/api/verspakketten/{verspakket.Id}", request);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
// ── GET /api/verspakketten — pagination & sorting ─────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Get_Pagination_ReturnsCorrectPage()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Aardappel Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Broccoli Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Courgette Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/verspakketten?skip=1&take=1");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetVerspakketten.Response>();
|
||||
body!.Verspakketten.Should().HaveCount(1);
|
||||
body.Verspakketten.First().Naam.Should().Be("Broccoli Pakket");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_SortDescending_ReturnsItemsInReverseOrder()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "AH",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Aardappel Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Zomerpakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var response = await Client.GetAsync("/api/verspakketten?sortDirection=Descending");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var body = await response.Content.ReadFromJsonAsync<GetVerspakketten.Response>();
|
||||
body!.Verspakketten.First().Naam.Should().Be("Zomerpakket");
|
||||
body.Verspakketten.Last().Naam.Should().Be("Aardappel Pakket");
|
||||
}
|
||||
|
||||
// ── POST /api/verspakketten/{id}/beoordelingen ────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task AddBeoordeling_ReturnsBadRequest_WhenVerspakketDoesNotExist()
|
||||
{
|
||||
var command = new AddBeoordeling.Command(Guid.NewGuid(), 8, 7, true, "Heerlijk!");
|
||||
var response = await Client.PostAsJsonAsync($"/api/verspakketten/{command.VerspakketId}/beoordelingen", command);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddBeoordeling_Returns201_WhenVerspakketExists()
|
||||
{
|
||||
var supermarkt = await SeedAsync(new Supermarkt
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Lidl",
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
var verspakket = await SeedAsync(new Verspakket
|
||||
{
|
||||
Id = Guid.NewGuid(), Naam = "Basis Pakket", AantalPersonen = 2,
|
||||
SupermarktId = supermarkt.Id,
|
||||
CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var command = new AddBeoordeling.Command(verspakket.Id, 8, 7, true, "Heerlijk!");
|
||||
var response = await Client.PostAsJsonAsync($"/api/verspakketten/{verspakket.Id}/beoordelingen", command);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
||||
var body = await response.Content.ReadFromJsonAsync<AddBeoordeling.Response>();
|
||||
body!.Id.Should().NotBeEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Lutra.Application.Interfaces;
|
||||
using Lutra.Infrastructure.Sql;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Lutra.API.IntegrationTests.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for integration tests. Provides a shared factory and helper methods
|
||||
/// to seed and reset the database between tests.
|
||||
/// </summary>
|
||||
public abstract class IntegrationTestBase : IClassFixture<LutraApiFactory>, IAsyncLifetime
|
||||
{
|
||||
protected readonly LutraApiFactory Factory;
|
||||
protected readonly HttpClient Client;
|
||||
|
||||
protected IntegrationTestBase(LutraApiFactory factory)
|
||||
{
|
||||
Factory = factory;
|
||||
Client = factory.CreateClient();
|
||||
}
|
||||
|
||||
/// <summary>Seed data or perform setup before each test.</summary>
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
Factory.EnsureSchemaCreated();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Reset database state after each test.</summary>
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ILutraDbContext>() as LutraDbContext;
|
||||
if (db is not null)
|
||||
{
|
||||
db.Beoordelingen.RemoveRange(db.Beoordelingen);
|
||||
db.Verspaketten.RemoveRange(db.Verspaketten);
|
||||
db.Supermarkten.RemoveRange(db.Supermarkten);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<T> SeedAsync<T>(T entity) where T : class
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<ILutraDbContext>() as LutraDbContext;
|
||||
db!.Set<T>().Add(entity);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Lutra.Application.Interfaces;
|
||||
using Lutra.Infrastructure.Sql;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Lutra.API.IntegrationTests.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Custom WebApplicationFactory that replaces the PostgreSQL database with SQLite in-memory
|
||||
/// so that integration tests can run without a live database server.
|
||||
/// A single SqliteConnection is kept open for the lifetime of the factory so that
|
||||
/// all DI scopes share the same in-memory database.
|
||||
/// </summary>
|
||||
public class LutraApiFactory : WebApplicationFactory<Program>
|
||||
{
|
||||
// Opened immediately so it is ready when ConfigureWebHost runs.
|
||||
private readonly SqliteConnection _connection = new("Data Source=:memory:");
|
||||
private bool _schemaCreated;
|
||||
|
||||
public LutraApiFactory()
|
||||
{
|
||||
_connection.Open();
|
||||
}
|
||||
|
||||
/// <summary>Ensures the SQLite schema is created. Call once before the first test.</summary>
|
||||
public void EnsureSchemaCreated()
|
||||
{
|
||||
if (_schemaCreated) return;
|
||||
|
||||
using var scope = Services.CreateScope();
|
||||
var db = (LutraDbContext)scope.ServiceProvider.GetRequiredService<ILutraDbContext>();
|
||||
db.Database.EnsureCreated();
|
||||
_schemaCreated = true;
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
// EF Core 10 stores provider configuration in IDbContextOptionsConfiguration<T>
|
||||
// descriptors (one per AddDbContext call). All four registration types must be
|
||||
// removed so neither Npgsql options nor its provider services survive into the
|
||||
// SQLite registration.
|
||||
services.RemoveAll<ILutraDbContext>();
|
||||
services.RemoveAll<LutraDbContext>();
|
||||
services.RemoveAll<DbContextOptions<LutraDbContext>>();
|
||||
services.RemoveAll<DbContextOptions>();
|
||||
services.RemoveAll(typeof(IDbContextOptionsConfiguration<LutraDbContext>));
|
||||
|
||||
// Register SQLite using the shared open connection.
|
||||
services.AddDbContext<ILutraDbContext, LutraDbContext>(options =>
|
||||
options.UseSqlite(_connection));
|
||||
});
|
||||
|
||||
builder.UseEnvironment("Testing");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
_connection.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lutra.API\Lutra.API.csproj" />
|
||||
<ProjectReference Include="..\Lutra.Infrastructure\Lutra.Infrastructure.Sql.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -85,12 +85,28 @@ namespace Lutra.API.Controllers
|
||||
/// </returns>
|
||||
[HttpPut("{id:guid}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Update(Guid id, [FromBody] UpdateVerspakketRequest request)
|
||||
{
|
||||
var command = new UpdateVerspakket.Command(id, request.Naam, request.PrijsInCenten, request.AantalPersonen, request.SupermarktId);
|
||||
await mediator.SendCommandAsync<UpdateVerspakket.Command, UpdateVerspakket.Response>(command);
|
||||
return NoContent();
|
||||
try
|
||||
{
|
||||
var command = new UpdateVerspakket.Command(id, request.Naam, request.PrijsInCenten, request.AantalPersonen, request.SupermarktId);
|
||||
await mediator.SendCommandAsync<UpdateVerspakket.Command, UpdateVerspakket.Response>(command);
|
||||
return NoContent();
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
}
|
||||
catch (InvalidOperationException ex) when (ex.Message.StartsWith($"Verspakket with id '{id}'"))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="FluentAssertions" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="Moq.EntityFrameworkCore" Version="10.0.0.2" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lutra.Application\Lutra.Application.csproj" />
|
||||
<ProjectReference Include="..\Lutra.Domain\Lutra.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,72 @@
|
||||
using FluentAssertions;
|
||||
using Lutra.Application.Interfaces;
|
||||
using Lutra.Application.Verspakketten;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using Moq.EntityFrameworkCore;
|
||||
|
||||
namespace Lutra.Application.UnitTests.Verspakketten;
|
||||
|
||||
public class AddBeoordelingHandlerTests
|
||||
{
|
||||
private readonly Mock<ILutraDbContext> _contextMock;
|
||||
private readonly AddBeoordeling.Handler _handler;
|
||||
|
||||
public AddBeoordelingHandlerTests()
|
||||
{
|
||||
_contextMock = new Mock<ILutraDbContext>();
|
||||
_handler = new AddBeoordeling.Handler(_contextMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_VerspakketExists_AddsBeoordeling()
|
||||
{
|
||||
var verspakketId = Guid.NewGuid();
|
||||
var verspakketten = new List<Domain.Entities.Verspakket>
|
||||
{
|
||||
new() { Id = verspakketId, Naam = "Test", AantalPersonen = 2, SupermarktId = Guid.NewGuid(), CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow }
|
||||
};
|
||||
|
||||
_contextMock.Setup(c => c.Verspaketten).ReturnsDbSet(verspakketten);
|
||||
_contextMock.Setup(c => c.Beoordelingen).ReturnsDbSet(new List<Domain.Entities.Beoordeling>());
|
||||
_contextMock.Setup(c => c.SaveChangesAsync(It.IsAny<CancellationToken>())).ReturnsAsync(1);
|
||||
|
||||
var command = new AddBeoordeling.Command(verspakketId, 8, 7, true, "Lekker!");
|
||||
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
result.Id.Should().NotBeEmpty();
|
||||
_contextMock.Verify(c => c.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_VerspakketNotFound_ThrowsInvalidOperationException()
|
||||
{
|
||||
_contextMock.Setup(c => c.Verspaketten).ReturnsDbSet(new List<Domain.Entities.Verspakket>());
|
||||
|
||||
var command = new AddBeoordeling.Command(Guid.NewGuid(), 8, 7, true, null);
|
||||
|
||||
var act = () => _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
await act.Should().ThrowAsync<InvalidOperationException>()
|
||||
.WithMessage("*was not found*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_VerspakketDeleted_ThrowsInvalidOperationException()
|
||||
{
|
||||
var verspakketId = Guid.NewGuid();
|
||||
var verspakketten = new List<Domain.Entities.Verspakket>
|
||||
{
|
||||
new() { Id = verspakketId, Naam = "Deleted", AantalPersonen = 2, SupermarktId = Guid.NewGuid(), CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow, DeletedAt = DateTime.UtcNow }
|
||||
};
|
||||
|
||||
_contextMock.Setup(c => c.Verspaketten).ReturnsDbSet(verspakketten);
|
||||
|
||||
var command = new AddBeoordeling.Command(verspakketId, 8, 7, true, null);
|
||||
|
||||
var act = () => _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
await act.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using FluentAssertions;
|
||||
using Lutra.Application.Interfaces;
|
||||
using Lutra.Application.Verspakketten;
|
||||
using Moq;
|
||||
using Moq.EntityFrameworkCore;
|
||||
|
||||
namespace Lutra.Application.UnitTests.Verspakketten;
|
||||
|
||||
public class CreateVerspakketHandlerTests
|
||||
{
|
||||
private readonly Mock<ILutraDbContext> _contextMock;
|
||||
private readonly CreateVerspakket.Handler _handler;
|
||||
|
||||
public CreateVerspakketHandlerTests()
|
||||
{
|
||||
_contextMock = new Mock<ILutraDbContext>();
|
||||
_handler = new CreateVerspakket.Handler(_contextMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_SupermarktExists_CreatesVerspakket()
|
||||
{
|
||||
var supermarktId = Guid.NewGuid();
|
||||
var supermarkten = new List<Domain.Entities.Supermarkt>
|
||||
{
|
||||
new() { Id = supermarktId, Naam = "AH", CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow }
|
||||
};
|
||||
|
||||
_contextMock.Setup(c => c.Supermarkten).ReturnsDbSet(supermarkten);
|
||||
_contextMock.Setup(c => c.Verspaketten).ReturnsDbSet(new List<Domain.Entities.Verspakket>());
|
||||
_contextMock.Setup(c => c.SaveChangesAsync(It.IsAny<CancellationToken>())).ReturnsAsync(1);
|
||||
|
||||
var command = new CreateVerspakket.Command("Lente Pakket", 1299, 2, supermarktId);
|
||||
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
result.Id.Should().NotBeEmpty();
|
||||
_contextMock.Verify(c => c.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_SupermarktNotFound_ThrowsInvalidOperationException()
|
||||
{
|
||||
_contextMock.Setup(c => c.Supermarkten).ReturnsDbSet(new List<Domain.Entities.Supermarkt>());
|
||||
|
||||
var command = new CreateVerspakket.Command("Lente Pakket", 1299, 2, Guid.NewGuid());
|
||||
|
||||
var act = () => _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
await act.Should().ThrowAsync<InvalidOperationException>()
|
||||
.WithMessage("*was not found*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_CreatesVerspakketWithCorrectProperties()
|
||||
{
|
||||
var supermarktId = Guid.NewGuid();
|
||||
var supermarkten = new List<Domain.Entities.Supermarkt>
|
||||
{
|
||||
new() { Id = supermarktId, Naam = "Jumbo", CreatedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow }
|
||||
};
|
||||
|
||||
Domain.Entities.Verspakket? savedVerspakket = null;
|
||||
_contextMock.Setup(c => c.Supermarkten).ReturnsDbSet(supermarkten);
|
||||
_contextMock.Setup(c => c.Verspaketten).ReturnsDbSet(new List<Domain.Entities.Verspakket>());
|
||||
_contextMock
|
||||
.Setup(c => c.Verspaketten.AddAsync(It.IsAny<Domain.Entities.Verspakket>(), It.IsAny<CancellationToken>()))
|
||||
.Callback<Domain.Entities.Verspakket, CancellationToken>((v, _) => savedVerspakket = v);
|
||||
_contextMock.Setup(c => c.SaveChangesAsync(It.IsAny<CancellationToken>())).ReturnsAsync(1);
|
||||
|
||||
var command = new CreateVerspakket.Command("Zomer Pakket", 999, 4, supermarktId);
|
||||
|
||||
await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
savedVerspakket.Should().NotBeNull();
|
||||
savedVerspakket!.Naam.Should().Be("Zomer Pakket");
|
||||
savedVerspakket.PrijsInCenten.Should().Be(999);
|
||||
savedVerspakket.AantalPersonen.Should().Be(4);
|
||||
savedVerspakket.SupermarktId.Should().Be(supermarktId);
|
||||
}
|
||||
}
|
||||
@@ -15,36 +15,118 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lutra.AppHost", "Lutra.AppH
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lutra.Infrastructure.Migrator", "Lutra.Infrastructure.Migrator\Lutra.Infrastructure.Migrator.csproj", "{6582486C-CEB7-78BF-D043-E0C3C0D6A923}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lutra.Application.UnitTests", "Lutra.Application.UnitTests\Lutra.Application.UnitTests.csproj", "{923A138F-A7A1-4254-A95F-447977B7AAC0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lutra.API.IntegrationTests", "Lutra.API.IntegrationTests\Lutra.API.IntegrationTests.csproj", "{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lutra.Infrastructure", "Lutra.Infrastructure", "{DF712D4B-6D10-CA62-6EF1-190F54D65E10}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{22B74CFE-E9D0-42F3-96E3-818D014E1A2E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CD66D294-FB25-4CA1-8DCA-7EF3DDDFE0C5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DACBC33C-A76A-483A-8535-AA62D33D4977}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0D9E0DD9-E914-483F-8046-8A57B510E984}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B9B41350-EB18-4564-81AB-C16F3E5A0CBB}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6582486C-CEB7-78BF-D043-E0C3C0D6A923}.Release|x86.Build.0 = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{923A138F-A7A1-4254-A95F-447977B7AAC0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E1B105D6-DCC2-42F5-9CB9-3A295804DCF6}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user