Add customer communication system

This commit is contained in:
sysadmin
2025-08-27 18:02:39 +01:00
parent 1f7c0af497
commit eae5be3e7c
136 changed files with 14552 additions and 97 deletions

View File

@@ -0,0 +1,165 @@
using FluentAssertions;
using TeleBot.Models;
using Xunit;
namespace TeleBot.Tests.Models
{
public class OrderFlowTests
{
[Fact]
public void NewOrderFlow_ShouldHaveDefaultValues()
{
// Arrange & Act
var orderFlow = new OrderFlowData();
// Assert
orderFlow.ShippingCountry.Should().Be("United Kingdom");
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingName);
orderFlow.UsePGPEncryption.Should().BeFalse();
orderFlow.IdentityReference.Should().BeNull();
}
[Fact]
public void OrderFlow_ShouldProgressThroughSteps()
{
// Arrange
var orderFlow = new OrderFlowData();
// Act & Assert - Step 1: Name
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingName);
orderFlow.ShippingName = "John Doe";
orderFlow.CurrentStep = OrderFlowStep.CollectingAddress;
// Step 2: Address
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingAddress);
orderFlow.ShippingAddress = "123 Main Street";
orderFlow.CurrentStep = OrderFlowStep.CollectingCity;
// Step 3: City
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingCity);
orderFlow.ShippingCity = "London";
orderFlow.CurrentStep = OrderFlowStep.CollectingPostCode;
// Step 4: PostCode
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingPostCode);
orderFlow.ShippingPostCode = "SW1A 1AA";
orderFlow.CurrentStep = OrderFlowStep.CollectingCountry;
// Step 5: Country
orderFlow.CurrentStep.Should().Be(OrderFlowStep.CollectingCountry);
orderFlow.ShippingCountry = "United Kingdom";
orderFlow.CurrentStep = OrderFlowStep.ReviewingOrder;
// Final validation
orderFlow.CurrentStep.Should().Be(OrderFlowStep.ReviewingOrder);
orderFlow.ShippingName.Should().Be("John Doe");
orderFlow.ShippingAddress.Should().Be("123 Main Street");
orderFlow.ShippingCity.Should().Be("London");
orderFlow.ShippingPostCode.Should().Be("SW1A 1AA");
orderFlow.ShippingCountry.Should().Be("United Kingdom");
}
[Fact]
public void OrderFlow_WithPGPEncryption_ShouldSetFlag()
{
// Arrange
var orderFlow = new OrderFlowData();
// Act
orderFlow.UsePGPEncryption = true;
// Assert
orderFlow.UsePGPEncryption.Should().BeTrue();
}
[Fact]
public void OrderFlow_WithNotes_ShouldStoreNotes()
{
// Arrange
var orderFlow = new OrderFlowData();
// Act
orderFlow.Notes = "Please leave at the front door";
// Assert
orderFlow.Notes.Should().Be("Please leave at the front door");
}
[Theory]
[InlineData(OrderFlowStep.CollectingName)]
[InlineData(OrderFlowStep.CollectingAddress)]
[InlineData(OrderFlowStep.CollectingCity)]
[InlineData(OrderFlowStep.CollectingPostCode)]
[InlineData(OrderFlowStep.CollectingCountry)]
[InlineData(OrderFlowStep.CollectingNotes)]
[InlineData(OrderFlowStep.ReviewingOrder)]
[InlineData(OrderFlowStep.SelectingPaymentMethod)]
[InlineData(OrderFlowStep.ProcessingPayment)]
[InlineData(OrderFlowStep.Complete)]
public void OrderFlowStep_AllSteps_ShouldBeDefined(OrderFlowStep step)
{
// Arrange
var orderFlow = new OrderFlowData();
// Act
orderFlow.CurrentStep = step;
// Assert
orderFlow.CurrentStep.Should().Be(step);
}
[Fact]
public void OrderFlow_SelectedCurrency_ShouldStore()
{
// Arrange
var orderFlow = new OrderFlowData();
// Act
orderFlow.SelectedCurrency = "BTC";
// Assert
orderFlow.SelectedCurrency.Should().Be("BTC");
}
[Fact]
public void OrderFlow_IdentityReference_ShouldStore()
{
// Arrange
var orderFlow = new OrderFlowData();
// Act
orderFlow.IdentityReference = "ANON-ABC123XYZ";
// Assert
orderFlow.IdentityReference.Should().Be("ANON-ABC123XYZ");
}
[Fact]
public void OrderFlow_CompleteFlow_ShouldHaveAllRequiredData()
{
// Arrange
var orderFlow = new OrderFlowData
{
IdentityReference = "ANON-TEST123",
ShippingName = "Jane Smith",
ShippingAddress = "456 Oak Avenue",
ShippingCity = "Manchester",
ShippingPostCode = "M1 1AA",
ShippingCountry = "United Kingdom",
Notes = "Ring doorbell twice",
SelectedCurrency = "XMR",
UsePGPEncryption = true,
CurrentStep = OrderFlowStep.Complete
};
// Assert
orderFlow.IdentityReference.Should().NotBeNullOrEmpty();
orderFlow.ShippingName.Should().NotBeNullOrEmpty();
orderFlow.ShippingAddress.Should().NotBeNullOrEmpty();
orderFlow.ShippingCity.Should().NotBeNullOrEmpty();
orderFlow.ShippingPostCode.Should().NotBeNullOrEmpty();
orderFlow.ShippingCountry.Should().NotBeNullOrEmpty();
orderFlow.CurrentStep.Should().Be(OrderFlowStep.Complete);
}
}
}

View File

@@ -0,0 +1,117 @@
using FluentAssertions;
using TeleBot.Models;
using Xunit;
namespace TeleBot.Tests.Models
{
public class PrivacySettingsTests
{
[Fact]
public void NewPrivacySettings_ShouldHaveSecureDefaults()
{
// Arrange & Act
var settings = new PrivacySettings();
// Assert
settings.UseEphemeralMode.Should().BeTrue("Ephemeral mode should be enabled by default for privacy");
settings.DisableAnalytics.Should().BeTrue("Analytics should be disabled by default for privacy");
settings.EnableDisappearingMessages.Should().BeTrue("Disappearing messages should be enabled by default");
settings.UseTorOnly.Should().BeFalse("Tor is optional");
settings.RequirePGP.Should().BeFalse("PGP is optional");
settings.DisappearingMessageTTL.Should().Be(30, "Default TTL should be 30 seconds");
}
[Fact]
public void PrivacySettings_CanToggleEphemeralMode()
{
// Arrange
var settings = new PrivacySettings();
// Act
settings.UseEphemeralMode = false;
// Assert
settings.UseEphemeralMode.Should().BeFalse();
}
[Fact]
public void PrivacySettings_CanEnableTor()
{
// Arrange
var settings = new PrivacySettings();
// Act
settings.UseTorOnly = true;
// Assert
settings.UseTorOnly.Should().BeTrue();
}
[Fact]
public void PrivacySettings_CanSetPGPKey()
{
// Arrange
var settings = new PrivacySettings();
var pgpKey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest key\n-----END PGP PUBLIC KEY BLOCK-----";
// Act
settings.RequirePGP = true;
settings.PGPPublicKey = pgpKey;
// Assert
settings.RequirePGP.Should().BeTrue();
settings.PGPPublicKey.Should().Be(pgpKey);
}
[Fact]
public void PrivacySettings_CanDisableAnalytics()
{
// Arrange
var settings = new PrivacySettings();
// Act
settings.DisableAnalytics = false;
// Assert
settings.DisableAnalytics.Should().BeFalse();
}
[Fact]
public void PrivacySettings_CanSetDisappearingMessageTTL()
{
// Arrange
var settings = new PrivacySettings();
// Act
settings.DisappearingMessageTTL = 60;
// Assert
settings.DisappearingMessageTTL.Should().Be(60);
}
[Fact]
public void PrivacySettings_MaxPrivacy_Configuration()
{
// Arrange
var settings = new PrivacySettings
{
UseEphemeralMode = true,
UseTorOnly = true,
RequirePGP = true,
DisableAnalytics = true,
EnableDisappearingMessages = true,
DisappearingMessageTTL = 10,
PGPPublicKey = "test-key"
};
// Assert - All privacy features should be enabled
settings.UseEphemeralMode.Should().BeTrue();
settings.UseTorOnly.Should().BeTrue();
settings.RequirePGP.Should().BeTrue();
settings.DisableAnalytics.Should().BeTrue();
settings.EnableDisappearingMessages.Should().BeTrue();
settings.DisappearingMessageTTL.Should().Be(10);
settings.PGPPublicKey.Should().NotBeNullOrEmpty();
}
}
}

View File

@@ -0,0 +1,234 @@
using System;
using System.Linq;
using FluentAssertions;
using TeleBot.Models;
using Xunit;
namespace TeleBot.Tests.Models
{
public class ShoppingCartTests
{
[Fact]
public void NewCart_ShouldBeEmpty()
{
// Arrange & Act
var cart = new ShoppingCart();
// Assert
cart.IsEmpty().Should().BeTrue();
cart.GetTotalItems().Should().Be(0);
cart.GetTotalAmount().Should().Be(0);
}
[Fact]
public void AddItem_ShouldAddToCart()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
// Act
cart.AddItem(productId, "Test Product", 10.50m, 2);
// Assert
cart.IsEmpty().Should().BeFalse();
cart.GetTotalItems().Should().Be(2);
cart.GetTotalAmount().Should().Be(21.00m);
cart.Items.Should().HaveCount(1);
cart.Items.First().ProductName.Should().Be("Test Product");
}
[Fact]
public void AddItem_SameProduct_ShouldIncreaseQuantity()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
// Act
cart.AddItem(productId, "Product A", 5.00m, 1);
cart.AddItem(productId, "Product A", 5.00m, 2);
// Assert
cart.Items.Should().HaveCount(1);
cart.Items.First().Quantity.Should().Be(3);
cart.GetTotalAmount().Should().Be(15.00m);
}
[Fact]
public void AddItem_DifferentProducts_ShouldAddSeparately()
{
// Arrange
var cart = new ShoppingCart();
var productId1 = Guid.NewGuid();
var productId2 = Guid.NewGuid();
// Act
cart.AddItem(productId1, "Product A", 10.00m, 1);
cart.AddItem(productId2, "Product B", 20.00m, 2);
// Assert
cart.Items.Should().HaveCount(2);
cart.GetTotalItems().Should().Be(3);
cart.GetTotalAmount().Should().Be(50.00m);
}
[Fact]
public void RemoveItem_ShouldRemoveFromCart()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
cart.AddItem(productId, "Test Product", 10.00m, 2);
// Act
cart.RemoveItem(productId);
// Assert
cart.IsEmpty().Should().BeTrue();
cart.GetTotalItems().Should().Be(0);
}
[Fact]
public void RemoveItem_NonExistent_ShouldNotThrow()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
// Act & Assert
var act = () => cart.RemoveItem(productId);
act.Should().NotThrow();
}
[Fact]
public void UpdateQuantity_ShouldUpdateExistingItem()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
cart.AddItem(productId, "Test Product", 10.00m, 2);
// Act
cart.UpdateQuantity(productId, 5);
// Assert
cart.Items.First().Quantity.Should().Be(5);
cart.GetTotalAmount().Should().Be(50.00m);
}
[Fact]
public void UpdateQuantity_ToZero_ShouldRemoveItem()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
cart.AddItem(productId, "Test Product", 10.00m, 2);
// Act
cart.UpdateQuantity(productId, 0);
// Assert
cart.IsEmpty().Should().BeTrue();
}
[Fact]
public void UpdateQuantity_Negative_ShouldRemoveItem()
{
// Arrange
var cart = new ShoppingCart();
var productId = Guid.NewGuid();
cart.AddItem(productId, "Test Product", 10.00m, 2);
// Act
cart.UpdateQuantity(productId, -1);
// Assert
cart.IsEmpty().Should().BeTrue();
}
[Fact]
public void Clear_ShouldEmptyCart()
{
// Arrange
var cart = new ShoppingCart();
cart.AddItem(Guid.NewGuid(), "Product A", 10.00m, 2);
cart.AddItem(Guid.NewGuid(), "Product B", 20.00m, 1);
// Act
cart.Clear();
// Assert
cart.IsEmpty().Should().BeTrue();
cart.GetTotalItems().Should().Be(0);
cart.GetTotalAmount().Should().Be(0);
}
[Fact]
public void CartItem_UpdateTotalPrice_ShouldCalculateCorrectly()
{
// Arrange
var item = new CartItem
{
UnitPrice = 15.50m,
Quantity = 3
};
// Act
item.UpdateTotalPrice();
// Assert
item.TotalPrice.Should().Be(46.50m);
}
[Fact]
public void Cart_UpdatedAt_ShouldUpdateOnModification()
{
// Arrange
var cart = new ShoppingCart();
var originalTime = cart.UpdatedAt;
System.Threading.Thread.Sleep(10);
// Act
cart.AddItem(Guid.NewGuid(), "Product", 10.00m, 1);
// Assert
cart.UpdatedAt.Should().BeAfter(originalTime);
}
[Theory]
[InlineData(10.99, 1, 10.99)]
[InlineData(5.50, 3, 16.50)]
[InlineData(0.99, 100, 99.00)]
[InlineData(123.45, 2, 246.90)]
public void GetTotalAmount_ShouldCalculateCorrectly(decimal price, int quantity, decimal expectedTotal)
{
// Arrange
var cart = new ShoppingCart();
// Act
cart.AddItem(Guid.NewGuid(), "Product", price, quantity);
// Assert
cart.GetTotalAmount().Should().Be(expectedTotal);
}
[Fact]
public void ComplexCart_ShouldCalculateCorrectTotals()
{
// Arrange
var cart = new ShoppingCart();
// Act
cart.AddItem(Guid.NewGuid(), "Laptop", 999.99m, 1);
cart.AddItem(Guid.NewGuid(), "Mouse", 25.50m, 2);
cart.AddItem(Guid.NewGuid(), "Keyboard", 75.00m, 1);
cart.AddItem(Guid.NewGuid(), "Monitor", 350.00m, 2);
// Assert
cart.Items.Should().HaveCount(4);
cart.GetTotalItems().Should().Be(6);
cart.GetTotalAmount().Should().Be(1825.99m);
}
}
}