From c4108600c98b9f88f6d759273d9e605e7755f495 Mon Sep 17 00:00:00 2001 From: 1-Bort-1 <323661610+1-Bort-1@users.noreply.github.com> Date: Thu, 10 Sep 2026 00:37:27 +0200 Subject: [PATCH] Give each test suite its own tempdir instead of the shared one Five test files wrote fixed names straight into tempdir(), which is /tmp when TMPDIR is unset and so shared by every suite on the machine. A second run's cleanup landing between one run's save and its isfile assertion fails that assertion. Each affected testset now opens a per-run mktempdir(). mktempdir() removes itself at process exit, so the hand cleanup that existed only to keep the shared directory tidy goes with it: test_plotting.jl's safe_rm helper and its call sites, the try/finally whose finally block had accumulated five of the save_plot tests, and the cleanup_test_files helpers in the yaml_geometry tests. test_plotting.jl's `!isdir(nested_dir) && @test !isdir(nested_dir)` becomes an unconditional assertion. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_014b7xG7wnJFW2vx2Ji5nwGW --- test/plotting/test_plotting.jl | 172 +++++++------------- test/ram_geometry/test_kite_geometry.jl | 16 +- test/yaml_geometry/test_load_polar_data.jl | 16 +- test/yaml_geometry/test_wing_constructor.jl | 45 ++--- 4 files changed, 79 insertions(+), 170 deletions(-) diff --git a/test/plotting/test_plotting.jl b/test/plotting/test_plotting.jl index b6a973ae..bf3e382c 100644 --- a/test/plotting/test_plotting.jl +++ b/test/plotting/test_plotting.jl @@ -24,23 +24,6 @@ using Test const makie_ext = Base.get_extension(VortexStepMethod, :VortexStepMethodMakieExt) -# Helper to robustly delete files on platforms with occasional file locks -safe_rm(path) = begin - if isfile(path) - try - rm(path; force=true) - catch - sleep(0.2) - try - rm(path; force=true) - catch - # last resort, ignore - end - end - end - nothing -end - global ram_wing = ram_air_matrix_wing(; n_panels=20, n_sections=4, alpha_range=deg2rad.(-1:1.0:1), delta_range=deg2rad.(-1:1.0:1)) @@ -72,7 +55,7 @@ function create_body_aero() end @testset "Plotting (Makie)" begin - save_dir = tempdir() + save_dir = mktempdir() body_aero = create_body_aero() fig = plot_geometry( @@ -88,22 +71,10 @@ end @test_throws MethodError VortexStepMethod.show_plot(nothing) @test_nowarn VortexStepMethod.show_plot(fig) - @test isfile(joinpath(save_dir, - "Rectangular_wing_geometry_angled_view.png")) - safe_rm(joinpath(save_dir, - "Rectangular_wing_geometry_angled_view.png")) - @test isfile(joinpath(save_dir, - "Rectangular_wing_geometry_front_view.png")) - safe_rm(joinpath(save_dir, - "Rectangular_wing_geometry_front_view.png")) - @test isfile(joinpath(save_dir, - "Rectangular_wing_geometry_side_view.png")) - safe_rm(joinpath(save_dir, - "Rectangular_wing_geometry_side_view.png")) - @test isfile(joinpath(save_dir, - "Rectangular_wing_geometry_top_view.png")) - safe_rm(joinpath(save_dir, - "Rectangular_wing_geometry_top_view.png")) + for view_name in ("angled", "front", "side", "top") + @test isfile(joinpath(save_dir, + "Rectangular_wing_geometry_$(view_name)_view.png")) + end # Initialize the solvers vsm_solver = Solver(body_aero; aerodynamic_model_type=VSM) @@ -144,7 +115,6 @@ end ) @test fig isa Figure @test isfile(joinpath(save_dir, "Rectangular_Wing_Polars.png")) - safe_rm(joinpath(save_dir, "Rectangular_Wing_Polars.png")) # Plot polars with CL vs CD (cl_over_cd=false) fig = plot_polars( @@ -224,7 +194,7 @@ end ) @test fig !== nothing - literature_csv = joinpath(tempdir(), "polar_literature_aoa.csv") + literature_csv = joinpath(save_dir, "polar_literature_aoa.csv") open(literature_csv, "w") do io write(io, "AOA,cl,cd,cs\n") write(io, "0.0,0.1,0.01,0.0\n") @@ -232,20 +202,16 @@ end write(io, "10.0,0.9,0.04,0.02\n") end - try - fig = plot_polars( - Solver[], - BodyAerodynamics[], - ["Literature"], - literature_path_list=[literature_csv], - title="Literature AOA Header", - is_save=false, - is_show=false, - ) - @test fig !== nothing - finally - safe_rm(literature_csv) - end + fig = plot_polars( + Solver[], + BodyAerodynamics[], + ["Literature"], + literature_path_list=[literature_csv], + title="Literature AOA Header", + is_save=false, + is_show=false, + ) + @test fig !== nothing # Unit tests for shared extract_literature_polar_data using DelimitedFiles @@ -285,7 +251,7 @@ end bad_data, "bad.csv") # CM coefficient extraction from literature data - cm_csv = tempname() * "_lit_cm.csv" + cm_csv = joinpath(save_dir, "lit_cm.csv") open(cm_csv, "w") do io_cm write(io_cm, "alpha,cl,cd,cs,cmx,cmy,cmz\n" * @@ -298,10 +264,9 @@ end @test Float64.(cm_result.cmx) == [0.001, 0.004] @test Float64.(cm_result.cmy) == [0.002, 0.005] @test Float64.(cm_result.cmz) == [0.003, 0.006] - safe_rm(cm_csv) # angle_type="side_slip" literature loading - beta_csv = tempname() * "_lit_beta.csv" + beta_csv = joinpath(save_dir, "lit_beta.csv") open(beta_csv, "w") do io_beta write(io_beta, "alpha,beta,cl,cd,cs\n" * @@ -312,10 +277,9 @@ end readdlm(beta_csv, ','), beta_csv; angle_type="side_slip") @test beta_result.polar_data[1] == [0.0, 5.0] - safe_rm(beta_csv) # Integration: literature CSV with AoA alias and no CS - lit_no_cs_path = tempname() * "_lit_no_cs.csv" + lit_no_cs_path = joinpath(save_dir, "lit_no_cs.csv") open(lit_no_cs_path, "w") do io_no_cs write(io_no_cs, "aoa,cl,cd\n0.0,0.10,0.010\n5.0,0.20,0.020\n") end @@ -328,10 +292,9 @@ end is_show=false ) @test fig_lit_no_cs !== nothing - safe_rm(lit_no_cs_path) # Integration: missing CD column should fail - lit_bad_path = tempname() * "_lit_bad.csv" + lit_bad_path = joinpath(save_dir, "lit_bad.csv") open(lit_bad_path, "w") do io_bad write(io_bad, "alpha,cl\n0.0,0.10\n5.0,0.20\n") end @@ -343,10 +306,9 @@ end is_save=false, is_show=false ) - safe_rm(lit_bad_path) # Test show_moments=true with literature data - cm_lit_path = tempname() * "_lit_moments.csv" + cm_lit_path = joinpath(save_dir, "lit_moments.csv") open(cm_lit_path, "w") do io_cm_lit write(io_cm_lit, "alpha,cl,cd,cs,cmx,cmy,cmz\n" * @@ -363,10 +325,9 @@ end is_show=false ) @test fig_moments !== nothing - safe_rm(cm_lit_path) # Test show_moments=false (default) - no_cm_path = tempname() * "_lit_no_cm.csv" + no_cm_path = joinpath(save_dir, "lit_no_cm.csv") open(no_cm_path, "w") do io_no_cm write(io_no_cm, "alpha,cl,cd\n" * @@ -382,7 +343,6 @@ end is_show=false ) @test fig_no_moments !== nothing - safe_rm(no_cm_path) # Tests for save_plot function @testset "_active_backend_prefers_vector_output" begin @@ -410,60 +370,40 @@ end active_backend_prefers_vector_output = getfield(makie_ext, :_active_backend_prefers_vector_output) - save_test_dir = tempdir() - - # Test 1: save_plot with explicit data_type (".png") - VortexStepMethod.save_plot(fig, save_test_dir, "test_explicit_png", data_type=".png") - @test isfile(joinpath(save_test_dir, "test_explicit_png.png")) - safe_rm(joinpath(save_test_dir, "test_explicit_png.png")) - - # Test 2: save_plot with explicit data_type (".pdf") - VortexStepMethod.save_plot(fig, save_test_dir, "test_explicit_pdf", data_type=".pdf") - @test isfile(joinpath(save_test_dir, "test_explicit_pdf.pdf")) - safe_rm(joinpath(save_test_dir, "test_explicit_pdf.pdf")) - - # Test 3: save_plot with data_type=nothing (backend-aware detection) - backend_aware_dir = mktempdir() - try - VortexStepMethod.save_plot(fig, backend_aware_dir, "test_backend_aware", data_type=nothing) - pdf_path = joinpath(backend_aware_dir, "test_backend_aware.pdf") - png_path = joinpath(backend_aware_dir, "test_backend_aware.png") - expected_ext = active_backend_prefers_vector_output(Makie) ? ".pdf" : ".png" - - @test xor(isfile(pdf_path), isfile(png_path)) - @test isfile(joinpath(backend_aware_dir, "test_backend_aware" * expected_ext)) - finally - safe_rm(joinpath(backend_aware_dir, "test_backend_aware.pdf")) - safe_rm(joinpath(backend_aware_dir, "test_backend_aware.png")) - rm(backend_aware_dir; force=true, recursive=true) - - # Test 4: save_plot with title containing spaces (should be sanitized to underscores) - VortexStepMethod.save_plot(fig, save_test_dir, "test with spaces", data_type=".png") - @test isfile(joinpath(save_test_dir, "test_with_spaces.png")) - safe_rm(joinpath(save_test_dir, "test_with_spaces.png")) - - # Test 5: save_plot with title containing percent signs (should be sanitized to "pct") - VortexStepMethod.save_plot(fig, save_test_dir, "test%efficiency", data_type=".png") - @test isfile(joinpath(save_test_dir, "testpctefficiency.png")) - safe_rm(joinpath(save_test_dir, "testpctefficiency.png")) - - # Test 6: save_plot with title containing both spaces and percent signs - VortexStepMethod.save_plot(fig, save_test_dir, "test %efficiency metric", data_type=".png") - @test isfile(joinpath(save_test_dir, "test_pctefficiency_metric.png")) - safe_rm(joinpath(save_test_dir, "test_pctefficiency_metric.png")) - - # Test 7: save_plot creates directory if it doesn't exist - nested_dir = joinpath(save_test_dir, "nested_save_plot_dir") - !isdir(nested_dir) && @test !isdir(nested_dir) - VortexStepMethod.save_plot(fig, nested_dir, "test_nested_dir", data_type=".png") - @test isdir(nested_dir) - @test isfile(joinpath(nested_dir, "test_nested_dir.png")) - safe_rm(joinpath(nested_dir, "test_nested_dir.png")) - rm(nested_dir; force=true) - - # Test 8: save_plot raises error when save_path is nothing - @test_throws ArgumentError VortexStepMethod.save_plot(fig, nothing, "test_title", data_type=".png") - end + # Explicit data_type picks the extension. + VortexStepMethod.save_plot(fig, save_dir, "test_explicit_png", data_type=".png") + @test isfile(joinpath(save_dir, "test_explicit_png.png")) + + VortexStepMethod.save_plot(fig, save_dir, "test_explicit_pdf", data_type=".pdf") + @test isfile(joinpath(save_dir, "test_explicit_pdf.pdf")) + + # data_type=nothing picks it from the active backend, and writes only that one. + VortexStepMethod.save_plot(fig, save_dir, "test_backend_aware", data_type=nothing) + pdf_path = joinpath(save_dir, "test_backend_aware.pdf") + png_path = joinpath(save_dir, "test_backend_aware.png") + expected_ext = active_backend_prefers_vector_output(Makie) ? ".pdf" : ".png" + @test xor(isfile(pdf_path), isfile(png_path)) + @test isfile(joinpath(save_dir, "test_backend_aware" * expected_ext)) + + # Spaces become underscores and percent signs become "pct" in the file name. + VortexStepMethod.save_plot(fig, save_dir, "test with spaces", data_type=".png") + @test isfile(joinpath(save_dir, "test_with_spaces.png")) + + VortexStepMethod.save_plot(fig, save_dir, "test%efficiency", data_type=".png") + @test isfile(joinpath(save_dir, "testpctefficiency.png")) + + VortexStepMethod.save_plot(fig, save_dir, "test %efficiency metric", data_type=".png") + @test isfile(joinpath(save_dir, "test_pctefficiency_metric.png")) + + # A save_path that does not exist yet is created. + nested_dir = joinpath(save_dir, "nested_save_plot_dir") + @test !isdir(nested_dir) + VortexStepMethod.save_plot(fig, nested_dir, "test_nested_dir", data_type=".png") + @test isdir(nested_dir) + @test isfile(joinpath(nested_dir, "test_nested_dir.png")) + + @test_throws ArgumentError VortexStepMethod.save_plot(fig, nothing, "test_title", + data_type=".png") end """ diff --git a/test/ram_geometry/test_kite_geometry.jl b/test/ram_geometry/test_kite_geometry.jl index 50e787de..4c9fdc8d 100644 --- a/test/ram_geometry/test_kite_geometry.jl +++ b/test/ram_geometry/test_kite_geometry.jl @@ -10,9 +10,9 @@ using Interpolations using Serialization @testset "Kite Geometry Tests" begin - # Test data - test_obj_path = joinpath(tempdir(), "test.obj") - test_dat_path = joinpath(tempdir(), "test.dat") + work_dir = mktempdir() + test_obj_path = joinpath(work_dir, "test.obj") + test_dat_path = joinpath(work_dir, "test.dat") @testset "OBJ File Reading" begin # Create minimal test OBJ file @@ -90,7 +90,6 @@ using Serialization end # Create test airfoil data file - test_dat_path = joinpath(tempdir(), "test.dat") write(test_dat_path, "1.0 0.0\n0.0 0.0\n-1.0 0.0\n") # Create polar data @@ -112,9 +111,9 @@ using Serialization cd_matrix[end] = NaN cm_matrix[end] = NaN - cl_polar_path = joinpath(tempdir(), test_dat_path[1:end-4] * "_cl_polar.csv") - cd_polar_path = joinpath(tempdir(), test_dat_path[1:end-4] * "_cd_polar.csv") - cm_polar_path = joinpath(tempdir(), test_dat_path[1:end-4] * "_cm_polar.csv") + cl_polar_path = test_dat_path[1:end-4] * "_cl_polar.csv" + cd_polar_path = test_dat_path[1:end-4] * "_cd_polar.csv" + cm_polar_path = test_dat_path[1:end-4] * "_cm_polar.csv" # Write matrices to CSV write_aero_matrix(cl_polar_path, cl_matrix, deg2rad.(alphas), deg2rad.(d_trailing_edge_angles), "C_l") @@ -175,7 +174,4 @@ using Serialization # Rebuild against ram_air_matrix_wing() geometry once its numerics are set. @test_skip false end - - rm(test_obj_path) - rm(test_dat_path) end diff --git a/test/yaml_geometry/test_load_polar_data.jl b/test/yaml_geometry/test_load_polar_data.jl index ccb487e1..190ada25 100644 --- a/test/yaml_geometry/test_load_polar_data.jl +++ b/test/yaml_geometry/test_load_polar_data.jl @@ -6,14 +6,9 @@ using YAML using Logging @testset "load_polar_data Function Tests" begin - # Setup temporary files for testing - test_csv_path = joinpath(tempdir(), "test_polar.csv") - - # Clean up function - function cleanup_test_files() - isfile(test_csv_path) && rm(test_csv_path; force=true) - end - + work_dir = mktempdir() + test_csv_path = joinpath(work_dir, "test_polar.csv") + @testset "Valid CSV File" begin # Create a valid CSV file with polar data csv_content = """alpha,cl,cd,cm @@ -72,7 +67,7 @@ using Logging end @testset "Missing File" begin - nonexistent_path = joinpath(tempdir(), "nonexistent.csv") + nonexistent_path = joinpath(work_dir, "nonexistent.csv") aero_data, aero_model = suppress_warnings(() -> load_polar_data(nonexistent_path)) @test aero_model == INVISCID @@ -120,7 +115,4 @@ using Logging @test aero_model == INVISCID @test aero_data === nothing end - - # Cleanup after all tests - cleanup_test_files() end diff --git a/test/yaml_geometry/test_wing_constructor.jl b/test/yaml_geometry/test_wing_constructor.jl index ac20d6a6..3ad6f944 100644 --- a/test/yaml_geometry/test_wing_constructor.jl +++ b/test/yaml_geometry/test_wing_constructor.jl @@ -6,32 +6,19 @@ using YAML using Logging @testset "Wing Constructor Tests" begin - # Setup temporary files for testing - test_yaml_path = joinpath(tempdir(), "test_wing.yaml") - test_polar_dir = joinpath(tempdir(), "polars") - - # Clean up function - function cleanup_test_files() - test_dir = dirname(test_yaml_path) - for file in [test_yaml_path, - joinpath(test_dir, "standard_airfoil.csv"), - joinpath(test_dir, "alternate_airfoil.csv")] - isfile(file) && rm(file; force=true) - end - isdir(test_polar_dir) && rm(test_polar_dir; recursive=true, force=true) - end - - # Create polar data directory and files + work_dir = mktempdir() + test_yaml_path = joinpath(work_dir, "test_wing.yaml") + test_polar_dir = joinpath(work_dir, "polars") + + # The YAML files under test reach their polars both through `polars/.csv` + # and by bare name beside the YAML, so each airfoil is copied to both places. mkpath(test_polar_dir) - - # Copy the actual polar files to the temp directory for tests that reference them - cp(test_data_path("yaml_geometry", "standard_airfoil.csv"), joinpath(test_polar_dir, "1.csv"); force=true) - cp(test_data_path("yaml_geometry", "alternate_airfoil.csv"), joinpath(test_polar_dir, "2.csv"); force=true) - - # Also copy them to the test directory itself for direct reference tests - test_dir = dirname(test_yaml_path) - cp(test_data_path("yaml_geometry", "standard_airfoil.csv"), joinpath(test_dir, "standard_airfoil.csv"); force=true) - cp(test_data_path("yaml_geometry", "alternate_airfoil.csv"), joinpath(test_dir, "alternate_airfoil.csv"); force=true) + for (airfoil, polar_name) in (("standard_airfoil.csv", "1.csv"), + ("alternate_airfoil.csv", "2.csv")) + source = test_data_path("yaml_geometry", airfoil) + cp(source, joinpath(test_polar_dir, polar_name)) + cp(source, joinpath(work_dir, airfoil)) + end @testset "Valid YAML Wing Construction" begin # Use the actual YAML file from the test data @@ -156,7 +143,7 @@ wing_airfoils: @testset "Relative Path Resolution" begin # Test that relative paths in CSV files are resolved relative to YAML file - subdir = joinpath(tempdir(), "subtest") + subdir = joinpath(work_dir, "subtest") mkpath(subdir) # Copy the simple wing file to subdirectory @@ -174,9 +161,6 @@ wing_airfoils: @test wing.unrefined_sections[1].aero_data isa Tuple @test wing.unrefined_sections[2].aero_model == POLAR_VECTORS @test wing.unrefined_sections[2].aero_data isa Tuple - - # Cleanup - rm(subdir; recursive=true) end @testset "Complex Wing Geometry" begin @@ -275,7 +259,4 @@ wing_airfoils: @test standard_wing isa Wing @test length(standard_wing.unrefined_sections) == 2 end - - # Cleanup after all tests - cleanup_test_files() end