From f6942e8b5bcf2d4f8b2d20ec61d791fb0a95e6d0 Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Thu, 2 Feb 2023 11:49:15 +0100 Subject: [PATCH] Added tests for data outputs. This closes issue #23. --- src/core/output.jl | 3 ++- test/io_tests.jl | 33 +++++++++++++++++++++++++-------- test/landscape_tests.jl | 32 -------------------------------- test/paramscan.toml | 2 ++ test/runtests.jl | 34 +++++++++++++++++++++++++++++++++- test/simulation_tests.jl | 15 +++++++++------ test/test_parameters.toml | 2 ++ 7 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/core/output.jl b/src/core/output.jl index 8bf8dcc..b6437ec 100644 --- a/src/core/output.jl +++ b/src/core/output.jl @@ -166,7 +166,8 @@ Cycle through all registered data outputs and activate them according to their configured frequency. """ function outputdata(model::AgentBasedModel) - #XXX all output functions are run on the first update (regardless of frequency) + #TODO enable output every X days + #XXX all output functions except for "end" are run on the first update # -> should they all be run on the last update, too? startdate = @param(core.startdate) isnextmonth = d -> (day(d) == day(startdate)) diff --git a/test/io_tests.jl b/test/io_tests.jl index 2180c59..2fb71c9 100644 --- a/test/io_tests.jl +++ b/test/io_tests.jl @@ -18,10 +18,7 @@ end @testset "Output functions" begin - properties = Dict{Symbol,Any}(:settings=>TESTSETTINGS, - :dataoutputs=>Vector{DataOutput}()) - space = GridSpace((10,10), periodic=false) - model = AgentBasedModel(Animal, space, properties=properties, warn=false) + model = smalltestlandscape() # test that the output directory is created with all files outdir = @param(core.outdir) Ps.createdatadir(outdir, @param(core.overwrite)) @@ -35,9 +32,29 @@ end @test isfile(joinpath(outdir, @param(core.configfile))) @test isfile(joinpath(outdir, Ps.LOGFILE)) # check whether the overwrite warning/protection works - logstring = "Overwriting existing output directory $(outdir)." - #TODO test overwrite protection - @test_logs (:warn, logstring) match_mode=:any Ps.createdatadir(outdir, @param(core.overwrite)) + @test_logs((:warn, "Overwriting existing output directory $(outdir)."), + match_mode=:any, + Ps.createdatadir(outdir, @param(core.overwrite))) + @test_throws ErrorException Ps.createdatadir(outdir, false) + # test that creating a DataOutput works, and outputs data with the required frequency + testoutput(model) = string(model.date)*"\n" + Ps.newdataoutput!(model, "never.csv", "Date", testoutput, "never") + Ps.newdataoutput!(model, "daily.csv", "Date", testoutput, "daily") + Ps.newdataoutput!(model, "monthly.csv", "Date", testoutput, "monthly") + Ps.newdataoutput!(model, "yearly.csv", "Date", testoutput, "yearly") + Ps.newdataoutput!(model, "end.csv", "Date", testoutput, "end") + @param(core.enddate) = Date(2023,2,1) + @test_logs((:info, "Simulated 366 days."), + match_mode=:any, + simulate!(Ps.withtestlogger(model))) + @test !isfile(joinpath(outdir, "never.csv")) + @test isfile(joinpath(outdir, "daily.csv")) + @test countlines(joinpath(outdir, "daily.csv")) == 367 + @test isfile(joinpath(outdir, "monthly.csv")) + @test countlines(joinpath(outdir, "monthly.csv")) == 14 + @test isfile(joinpath(outdir, "yearly.csv")) + @test countlines(joinpath(outdir, "yearly.csv")) == 3 + @test isfile(joinpath(outdir, "end.csv")) + @test countlines(joinpath(outdir, "end.csv")) == 2 rm(outdir, force=true, recursive=true) - #TODO test that creating a DataOutput works, and outputs data with the required frequency end diff --git a/test/landscape_tests.jl b/test/landscape_tests.jl index 7e338e9..e989fdb 100644 --- a/test/landscape_tests.jl +++ b/test/landscape_tests.jl @@ -3,38 +3,6 @@ ### These are the tests for the core landscape functions. ### -""" - smalltestlandscape() - -Create a 6x6 landscape with three land cover types for testing: - - F F F F F F - F F F F F F - F F F F F F - F F F F F W - F F G G G G - F F G G G G -""" -function smalltestlandscape() - landscape = Matrix{Pixel}(undef, 6, 6) - for x in 1:6 - for y in 1:6 - (x in (1:2) || y in (1:4)) ? lc = Ps.forest : lc = Ps.grass - landscape[x,y] = Pixel(lc, missing, []) - end - end - landscape[6,4] = Pixel(Ps.water, 0, []) - space = GridSpace(size(landscape), periodic=false) - properties = Dict{Symbol,Any}(:date=>TESTSETTINGS["core.startdate"], - :landscape=>landscape, - :events=>Vector{FarmEvent}(), - :logger=>global_logger(), - :dataoutputs=>Vector{DataOutput}(), - :settings=>TESTSETTINGS) - return AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space, properties=properties, - rng=StableRNG(TESTSETTINGS["core.seed"]), warn=false) -end - @testset "Landscape initialisation" begin # initialise the landscape part of the model landscape = Ps.initlandscape(TESTSETTINGS["core.landcovermap"], diff --git a/test/paramscan.toml b/test/paramscan.toml index cd3f513..ec44c3e 100644 --- a/test/paramscan.toml +++ b/test/paramscan.toml @@ -3,6 +3,8 @@ ### This configuration file is intended to test the parameter scanning feature. ### +#XXX remember that changes here may break tests! + [core] configfile = "test/paramscan.toml" # location of the configuration file landcovermap = "landcover_jena.tif" # location of the landcover map diff --git a/test/runtests.jl b/test/runtests.jl index 1542cc2..24aea56 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,6 +20,38 @@ const Ps = Persephone const TESTPARAMETERS = joinpath(pkgdir(Persephone), "test/test_parameters.toml") const TESTSETTINGS = Ps.getsettings(TESTPARAMETERS) +""" + smalltestlandscape() + +Create a 6x6 landscape with three land cover types for testing: + + F F F F F F + F F F F F F + F F F F F F + F F F F F W + F F G G G G + F F G G G G +""" +function smalltestlandscape() + landscape = Matrix{Pixel}(undef, 6, 6) + for x in 1:6 + for y in 1:6 + (x in (1:2) || y in (1:4)) ? lc = Ps.forest : lc = Ps.grass + landscape[x,y] = Pixel(lc, missing, []) + end + end + landscape[6,4] = Pixel(Ps.water, 0, []) + space = GridSpace(size(landscape), periodic=false) + properties = Dict{Symbol,Any}(:date=>TESTSETTINGS["core.startdate"], + :landscape=>landscape, + :events=>Vector{FarmEvent}(), + :logger=>global_logger(), + :dataoutputs=>Vector{DataOutput}(), + :settings=>TESTSETTINGS) + return AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space, properties=properties, + rng=StableRNG(TESTSETTINGS["core.seed"]), warn=false) +end + @testset "Persephone Tests" begin @testset "Core model" begin include("io_tests.jl") @@ -40,5 +72,5 @@ end # NOTE: Due to an issue with Julia (https://github.com/JuliaLang/julia/issues/48456), # whenever we are using `@test_logs` with a function that takes a model object, we have -# to wrap that model object in `withtestlogger()`. (For an example, see the "Model +# to wrap that model object in `Ps.withtestlogger()`. (For an example, see the "Model # simulation" testset in simulation_tests.jl.) diff --git a/test/simulation_tests.jl b/test/simulation_tests.jl index 7701033..678bf3f 100644 --- a/test/simulation_tests.jl +++ b/test/simulation_tests.jl @@ -17,22 +17,25 @@ end @testset "Parameter scanning" begin config = "paramscan.toml" - testdirs = ["results_test_paramscan/seed_1_loglevel_debug_overwrite_ask", - "results_test_paramscan/seed_1_loglevel_debug_overwrite_true", + testdirs = ["results_test_paramscan/seed_1_loglevel_warn_overwrite_ask", + "results_test_paramscan/seed_1_loglevel_warn_overwrite_true", "results_test_paramscan/seed_2_loglevel_info_overwrite_true"] settings = Ps.getsettings(config) scanparams = settings["internal.scanparams"] @test length(scanparams) == 3 @test sort(["core.overwrite", "core.loglevel", "core.seed"]) == sort(scanparams) scan = Ps.paramscan(settings, scanparams) - outdirs = (s["core.outdir"] for s in scan) + outdirs = map(s -> s["core.outdir"], scan) @test length(outdirs) == 12 - @test length(initialise(config)) == 12 #XXX This takes a long time + #TODO while parallelisation doesn't work yet, initialising 12 models takes too + # long to do every time the test suite is run. Therefore, I'm commenting out + # some tests here, to be reinstated once parallelisation is implemented. + #@test length(initialise(config)) == 12 for dir in testdirs @test dir in outdirs - @test isdir(dir) + #@test isdir(dir) end - rm("results_test_paramscan", force=true, recursive=true) + #rm("results_test_paramscan", force=true, recursive=true) end @testset "Model simulation" begin diff --git a/test/test_parameters.toml b/test/test_parameters.toml index 7c8891d..45f37a3 100644 --- a/test/test_parameters.toml +++ b/test/test_parameters.toml @@ -3,6 +3,8 @@ ### This configuration file is used for the test suite. ### +#XXX remember that changes here may break tests! + [core] configfile = "test_parameters.toml" # location of the configuration file landcovermap = "landcover_jena.tif" # location of the landcover map -- GitLab