Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Model Code Refactor #9

Merged
merged 17 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 23 additions & 28 deletions .github/workflows/unit-tests.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Unit Tests
name: Unit Tests

on:
push:
Expand All @@ -7,41 +7,36 @@ on:
branches: [ "main" ]
release:
types: [ published ]
workflow_dispatch: {}
workflow_dispatch: { }

permissions:
contents: read
actions: read
checks: write

jobs:
build:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 16

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x

- name: Restore dependencies
run: dotnet restore
- name: .NET Build
run: dotnet build

- name: Build
run: dotnet build --no-restore

- name: run
run: |
dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=unit_results.xml"
- name: .NET Test
run: |
dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=unit_results.xml"

- name: Test Report
uses: dorny/test-reporter@v1
if: success()
with:
name: Unit Tests
path: SVSModel.Tests/unit_results.xml
reporter: java-junit
- name: Test Report
uses: dorny/test-reporter@v1
if: success()
with:
name: Unit Tests
path: SVSModel.Tests/unit_results.xml
reporter: java-junit
139 changes: 139 additions & 0 deletions SVSModel.Tests/Configuration/CropConfigTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using SVSModel.Configuration;
using SVSModel.Models;
using Xunit;

namespace SVSModel.Tests.Configuration;

public class CropConfigTests
{
private static readonly string CropNameFull = Defaults.CurrentCropNameFull;
private static readonly string EstablishStage = Defaults.EstablishStage;
private static readonly string HarvestStage = Defaults.HarvestStage;
private static readonly double FieldLoss = Defaults.FieldLoss;
private static readonly double MoistureContent = Defaults.MoistureContent;
private static readonly DateTime EstablishDate = Defaults.EstablishDate;
private static readonly DateTime HarvestDate = Defaults.HarvestDate;
private static readonly string ResidueRemoval = Defaults.ResidueRemoval;
private static readonly string ResidueIncorporation = Defaults.ResidueIncorporation;
private static readonly double FieldYield = Defaults.FieldYield;
private static readonly string YieldUnits = Defaults.Units;
private static readonly double? Population = null;

private readonly Dictionary<string, object> ExcelInputDict = new()
{
{ "CurrentCropNameFull", CropNameFull },
{ "CurrentEstablishStage", EstablishStage },
{ "CurrentHarvestStage", HarvestStage },
{ "CurrentFieldLoss", FieldLoss },
{ "CurrentMoistureContent", MoistureContent },
{ "CurrentEstablishDate", EstablishDate },
{ "CurrentHarvestDate", HarvestDate },
{ "CurrentResidueRemoval", ResidueRemoval },
{ "CurrentResidueIncorporation", ResidueIncorporation },
{ "CurrentSaleableYield", FieldYield },
{ "CurrentYieldUnits", YieldUnits },
{ "CurrentPopulation", Population }
};

[Theory]
[InlineData(10.0, "t/ha")]
[InlineData(10_000.0, "kg/ha")]
[InlineData(0.25, "kg/head", 25_000.0)]
public void Test_CropConfig_Excel_Sets_Yield_Correctly(double yield, string units, double? population = null)
{
// Update values in the base dictionary
ExcelInputDict["CurrentSaleableYield"] = yield;
ExcelInputDict["CurrentYieldUnits"] = units;
if (population.HasValue) ExcelInputDict["CurrentPopulation"] = population;

var cropConfig = new CropConfig(ExcelInputDict, "Current");

// Determine the expected yield
var expectedFieldYield = yield * Constants.UnitConversions[units];
if (population.HasValue) expectedFieldYield = yield * population.Value;

Assert.Equal(cropConfig.FieldYield, expectedFieldYield);
}

[Fact]
public void Test_CropConfig_Excel_Sets_Residues_Correctly()
{
var cropConfig = new CropConfig(ExcelInputDict, "Current");

var expectedResidueFactRetained = Constants.ResidueFactRetained[ResidueRemoval];
Assert.Equal(cropConfig.ResidueFactRetained, expectedResidueFactRetained);

var expectedResidueFactIncorporated = Constants.ResidueIncorporation[ResidueIncorporation];
Assert.Equal(cropConfig.ResidueFactIncorporated, expectedResidueFactIncorporated);
}

[Theory]
[InlineData(10.0, "t/ha")]
[InlineData(10_000.0, "kg/ha")]
[InlineData(0.25, "kg/head", 25_000.0)]
public void Test_CropConfig_WebApp_Sets_Yield_Correctly(double yield, string units, double? population = null)
{
var cropConfig = new CropConfig
{
CropNameFull = CropNameFull,
EstablishStage = EstablishStage,
HarvestStage = HarvestStage,
FieldLoss = FieldLoss,
MoistureContent = MoistureContent,
EstablishDate = EstablishDate,
HarvestDate = HarvestDate,
_residueRemoval = ResidueRemoval,
_residueIncorporation = ResidueIncorporation,
_rawYield = yield,
_yieldUnits = units,
_population = population
};

// Determine the expected yield
var expectedFieldYield = yield * Constants.UnitConversions[units];
if (population.HasValue) expectedFieldYield = yield * population.Value;

Assert.Equal(cropConfig.FieldYield, expectedFieldYield);
}

[Theory]
[InlineData(10.0, "t/ha")]
[InlineData(10_000.0, "kg/ha")]
[InlineData(0.25, "kg/head", 25_000.0)]
public void Test_CropConfig_Both_Constructors_Match(double yield, string units, double? population = null)
{
var cropConfig = new CropConfig
{
CropNameFull = CropNameFull,
EstablishStage = EstablishStage,
HarvestStage = HarvestStage,
FieldLoss = FieldLoss,
MoistureContent = MoistureContent,
EstablishDate = EstablishDate,
HarvestDate = HarvestDate,
_residueRemoval = ResidueRemoval,
_residueIncorporation = ResidueIncorporation,
_rawYield = yield,
_yieldUnits = units,
_population = population
};

ExcelInputDict["CurrentSaleableYield"] = yield;
ExcelInputDict["CurrentYieldUnits"] = units;
if (population.HasValue) ExcelInputDict["CurrentPopulation"] = population;
var cropConfigExcel = new CropConfig(ExcelInputDict, "Current");

Assert.Equal(cropConfig.CropNameFull, cropConfigExcel.CropNameFull);
Assert.Equal(cropConfig.EstablishStage, cropConfigExcel.EstablishStage);
Assert.Equal(cropConfig.HarvestStage, cropConfigExcel.HarvestStage);
Assert.Equal(cropConfig.FieldLoss, cropConfigExcel.FieldLoss);
Assert.Equal(cropConfig.MoistureContent, cropConfigExcel.MoistureContent);
Assert.Equal(cropConfig.EstablishDate, cropConfigExcel.EstablishDate);
Assert.Equal(cropConfig.HarvestDate, cropConfigExcel.HarvestDate);
Assert.Equal(cropConfig.FieldYield, cropConfigExcel.FieldYield);
Assert.Equal(cropConfig.ResidueFactIncorporated, cropConfigExcel.ResidueFactIncorporated);
Assert.Equal(cropConfig.ResidueFactRetained, cropConfigExcel.ResidueFactRetained);
}
}
79 changes: 79 additions & 0 deletions SVSModel.Tests/Configuration/FieldConfigTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using SVSModel.Configuration;
using SVSModel.Models;
using Xunit;

namespace SVSModel.Tests.Configuration;

public class FieldConfigTests
{
private static readonly string SoilCategory = Defaults.SoilCategory;
private static readonly string Texture = Defaults.SoilTexture;
private static readonly double PMN = Defaults.PMN;
private static readonly int Splits = Defaults.Splits;
private static readonly double Rocks = 10;
private static readonly string SampleDepth = Defaults.SampleDepth;
private static readonly string PrePlantRain = Defaults.RainPrior;
private static readonly string InCropRain = Defaults.RainDuring;
private static readonly string Irrigation = Defaults.IrrigationApplied;

private readonly Dictionary<string, object> ExcelInputDict = new()
{
{ "SoilCategory", SoilCategory },
{ "Texture", Texture },
{ "PMN", PMN },
{ "Splits", Splits },
{ "Rocks", Rocks },
{ "SampleDepth", SampleDepth },
{ "PrePlantRain", PrePlantRain },
{ "InCropRain", InCropRain },
{ "Irrigation", Irrigation }
};

[Fact]
public void Test_FieldConfig_Excel_Gets_Values_Correctly()
{
var fieldConfig = new FieldConfig(ExcelInputDict);

Assert.Equal(fieldConfig.Rocks, Rocks / 100);
Assert.Equal(fieldConfig.SampleDepthFactor, Constants.SampleDepthFactor[SampleDepth]);
Assert.Equal(fieldConfig.BulkDensity, Constants.ParticleDensity[SoilCategory] * Constants.Porosity[Texture]);
Assert.Equal(fieldConfig.AWC, 3 * Constants.AWCpct[Texture] * (1 - Rocks / 100));
Assert.Equal(fieldConfig.PrePlantRainFactor, Constants.PPRainFactors[PrePlantRain]);
Assert.Equal(fieldConfig.InCropRainFactor, Constants.ICRainFactors[InCropRain]);
Assert.Equal(fieldConfig.IrrigationTrigger, Constants.IrrigationTriggers[Irrigation]);
Assert.Equal(fieldConfig.IrrigationRefill, Constants.IrrigationRefill[Irrigation]);
}

[Fact]
public void Test_FieldConfig_Both_Constructors_Match()
{
var fieldConfig = new FieldConfig
{
SoilCategory = SoilCategory,
SoilTexture = Texture,
PMN = PMN,
Splits = Splits,
_rawRocks = Rocks,
_sampleDepth = SampleDepth,
_prePlantRain = PrePlantRain,
_inCropRain = InCropRain,
_irrigation = Irrigation
};

var fieldConfigExcel = new FieldConfig(ExcelInputDict);

Assert.Equal(fieldConfig.SoilCategory, fieldConfigExcel.SoilCategory);
Assert.Equal(fieldConfig.SoilTexture, fieldConfigExcel.SoilTexture);
Assert.Equal(fieldConfig.Rocks, fieldConfigExcel.Rocks);
Assert.Equal(fieldConfig.SampleDepthFactor, fieldConfigExcel.SampleDepthFactor);
Assert.Equal(fieldConfig.BulkDensity, fieldConfigExcel.BulkDensity);
Assert.Equal(fieldConfig.PMN, fieldConfigExcel.PMN);
Assert.Equal(fieldConfig.Splits, fieldConfigExcel.Splits);
Assert.Equal(fieldConfig.AWC, fieldConfigExcel.AWC);
Assert.Equal(fieldConfig.PrePlantRainFactor, fieldConfigExcel.PrePlantRainFactor);
Assert.Equal(fieldConfig.InCropRainFactor, fieldConfigExcel.InCropRainFactor);
Assert.Equal(fieldConfig.IrrigationTrigger, fieldConfigExcel.IrrigationTrigger);
Assert.Equal(fieldConfig.IrrigationRefill, fieldConfigExcel.IrrigationRefill);
}
}
3 changes: 2 additions & 1 deletion SVSModel.Tests/SVSModel.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
20 changes: 0 additions & 20 deletions SVSModel.Tests/SVSModelTest.cs

This file was deleted.

14 changes: 10 additions & 4 deletions SVSModel/Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@ public class Config
public CropConfig Prior { get; set; }
public CropConfig Current { get; set; }
public CropConfig Following { get; set; }

public List<CropConfig> Rotation = new List<CropConfig>();

public List<CropConfig> Rotation { get; set; } = [];
public FieldConfig Field { get; set; }

/// <summary>
/// Constructor used only by external webapp
/// </summary>
public Config() { }

/// <summary>
/// Constructor used only by the Excel model
/// </summary>
public Config(Dictionary<string, object> c)
{
// Only raw input values should be set in here

Prior = new CropConfig(c, "Prior");
Current = new CropConfig(c, "Current");
Following = new CropConfig(c, "Following");
Rotation = new List<CropConfig> { Prior, Current, Following };
Rotation = [Prior, Current, Following];
Field = new FieldConfig(c);
}
}
Expand Down
Loading
Loading