Files
mikhail eae7c066d1 feat: Factorio Space Age Production Calculator
- Domain: immutable entities (Resource, Recipe, Machine, Module, etc.)
- Data: JSON recipe repository (34 resources, 26 recipes, Space Age)
- Solver: DFS-based production planner with module support
- Reporting: Console, JSON, Excel exporters
- CLI: solve/list commands with Spectre.Console
- Tests: 20 unit tests (xUnit) all passing
- Tech: C# .NET 10, MathNet.Numerics, ClosedXML

Model: GPT-4.1 (OpenAI) — executed by pi coding agent
2026-07-02 13:08:25 +03:00

115 lines
3.2 KiB
C#

using FactorioCalc.Domain;
using Xunit;
namespace FactorioCalc.Tests;
public class DomainTests
{
[Fact]
public void Resource_ValidConstructor_Succeeds()
{
var resource = new Resource(1, "Iron Ore");
Assert.Equal(1, resource.Id);
Assert.Equal("Iron Ore", resource.Name);
Assert.Equal("Iron Ore", resource.ToString());
}
[Fact]
public void Resource_EmptyName_Throws()
{
Assert.Throws<ArgumentException>(() => new Resource(1, ""));
Assert.Throws<ArgumentException>(() => new Resource(1, " "));
Assert.Throws<ArgumentException>(() => new Resource(1, null!));
}
[Fact]
public void Ingredient_ValidConstructor_Succeeds()
{
var ingredient = new Ingredient(1, 2.5);
Assert.Equal(1, ingredient.ResourceId);
Assert.Equal(2.5, ingredient.Amount);
}
[Fact]
public void Ingredient_NegativeAmount_Throws()
{
Assert.Throws<ArgumentException>(() => new Ingredient(1, -1));
}
[Fact]
public void Product_ValidConstructor_Succeeds()
{
var product = new Product(7, 1.0);
Assert.Equal(7, product.ResourceId);
Assert.Equal(1.0, product.Amount);
}
[Fact]
public void Product_ZeroAmount_Throws()
{
Assert.Throws<ArgumentException>(() => new Product(7, 0));
}
[Fact]
public void Machine_ValidConstructor_Succeeds()
{
var machine = new Machine(1, "Smelter", 0.5, 3.0, 2, new[] { "smelting" });
Assert.Equal(1, machine.Id);
Assert.Equal("Smelter", machine.Name);
Assert.Equal(0.5, machine.CraftingSpeed);
Assert.Equal(2, machine.ModuleSlots);
}
[Fact]
public void Machine_ZeroCraftingSpeed_Throws()
{
Assert.Throws<ArgumentException>(() => new Machine(1, "X", 0, 0, 0, Array.Empty<string>()));
}
[Fact]
public void Module_ValidConstructor_Succeeds()
{
var module = new Module(1, "Speed Module 1", ModuleType.Speed, 0.10, 0, -0.05);
Assert.Equal(ModuleType.Speed, module.Type);
Assert.Equal(0.10, module.SpeedBonus);
}
[Fact]
public void RecipeExecution_ValidConstructor_Succeeds()
{
var exec = new RecipeExecution(1, 5, 3, 10.5, Array.Empty<Module>(), 0.5, 0);
Assert.Equal(1, exec.RecipeId);
Assert.Equal(5, exec.MachineId);
Assert.Equal(3, exec.MachineCount);
Assert.Equal(10.5, exec.RecipeRate);
}
[Fact]
public void RecipeExecution_ZeroMachineCount_Throws()
{
Assert.Throws<ArgumentException>(() =>
new RecipeExecution(1, 5, 0, 10, Array.Empty<Module>(), 0.5, 0));
}
[Fact]
public void ProductionTarget_ValidConstructor_Succeeds()
{
var target = new ProductionTarget(30, 10);
Assert.Equal(30, target.ResourceId);
Assert.Equal(10, target.AmountPerSecond);
}
[Fact]
public void ProductionResult_ValidConstructor_Succeeds()
{
var result = new ProductionResult(
Array.Empty<RecipeExecution>(),
new Dictionary<int, double>(),
new Dictionary<int, double>());
Assert.Empty(result.Executions);
Assert.Empty(result.ResourceFlows);
Assert.Empty(result.RequiredInputs);
}
}