1+ @testsnippet deps_export_atp begin
2+ using EzXML
3+ end
4+
5+ # TODO : test if serialization works properly if uncertain types are used (Measurements)
6+
7+ @testitem " ImportExport(export_data::atp): export LineCableSystem -> LCC data" setup = [defaults, cable_system_export, deps_export_atp] begin
8+
9+
10+ # 1. ARRANGE & ACT: Run the export in a temporary directory
11+ mktempdir (joinpath (@__DIR__ )) do tmpdir
12+ output_file = joinpath (tmpdir, " atp_export_test.xml" )
13+ result_path = export_data (:atp , cable_system, earth_props, file_name= output_file)
14+ expected_file = joinpath (dirname (output_file), " $(cable_system. system_id) _$(basename (output_file)) " )
15+
16+ # 2. ASSERT: Basic file checks (exporter prefixes basename with system_id)
17+ @test result_path == expected_file
18+ @test isfile (expected_file)
19+ @test filesize (expected_file) > 500
20+
21+ # 3. ASSERT: General XML structure and LCC data
22+ @info " Performing high-level XML structure checks..."
23+ doc = readxml (expected_file)
24+ root_node = root (doc)
25+
26+ @test nodename (root_node) == " project"
27+ @test root_node[" Application" ] == " ATPDraw"
28+
29+ # Find the main LCC component content node
30+ comp_content_node = findfirst (" /project/objects/comp/comp_content" , root_node)
31+ @test ! isnothing (comp_content_node)
32+
33+ # Verify general parameters like Length, Freq, and Ground Resistivity
34+ @info " Verifying general LCC data (Length, Freq, Grnd resis)..."
35+ @test parse (Float64, findfirst (" data[@Name='Length']" , comp_content_node)[" Value" ]) ≈ cable_system. line_length
36+ @test parse (Float64, findfirst (" data[@Name='Freq']" , comp_content_node)[" Value" ]) ≈ problem_atp. frequencies[1 ]
37+ @test parse (Float64, findfirst (" data[@Name='Grnd resis']" , comp_content_node)[" Value" ]) ≈ problem_atp. earth_props. layers[end ]. base_rho_g
38+
39+ # 4. ASSERT: Detailed validation of ALL cables and conductors
40+ @info " Verifying all cables and their conductors..."
41+ lcc_node = findfirst (" /project/objects/comp/LCC" , root_node)
42+ cable_header = findfirst (" cable_header" , lcc_node)
43+ cable_nodes = findall (" cable" , cable_header)
44+
45+ @test length (cable_nodes) == num_phases
46+
47+ # Loop through each cable exported in the XML and compare it to the source
48+ for (i, cable_node) in enumerate (cable_nodes)
49+ @info " -> Checking Cable #$i ..."
50+ source_cable = cable_system. cables[i]
51+
52+ # Verify position of EACH cable
53+ @test parse (Float64, cable_node[" PosX" ]) ≈ source_cable. horz
54+ @test parse (Float64, cable_node[" PosY" ]) ≈ source_cable. vert
55+
56+ # Verify the number of conductor components inside this cable
57+ num_components = length (source_cable. design_data. components)
58+ @test parse (Int, cable_node[" NumCond" ]) == num_components
59+
60+ conductor_nodes = findall (" conductor" , cable_node)
61+ @test length (conductor_nodes) == num_components
62+
63+ # Loop through each conductor component within the cable
64+ for (j, conductor_node) in enumerate (conductor_nodes)
65+ source_component = source_cable. design_data. components[j]
66+ cond_group = source_component. conductor_group
67+ cond_props = source_component. conductor_props
68+ ins_group = source_component. insulator_group
69+ ins_props = source_component. insulator_props
70+
71+ expected_radius_in = cond_group. radius_in
72+ expected_radius_ext = cond_group. radius_ext
73+ expected_rho = cond_props. rho
74+ expected_muC = cond_props. mu_r
75+ expected_epsI = ins_props. eps_r
76+ expected_muI = ins_props. mu_r
77+ expected_Cext = ins_group. shunt_capacitance
78+ expected_Gext = ins_group. shunt_conductance
79+
80+ # Assert that every attribute matches the expected value
81+ @test parse (Float64, conductor_node[" Rin" ]) ≈ expected_radius_in
82+ @test parse (Float64, conductor_node[" Rout" ]) ≈ expected_radius_ext
83+ @test parse (Float64, conductor_node[" rho" ]) ≈ expected_rho
84+ @test parse (Float64, conductor_node[" muC" ]) ≈ expected_muC
85+ @test parse (Float64, conductor_node[" muI" ]) ≈ expected_muI
86+ @test parse (Float64, conductor_node[" epsI" ]) ≈ expected_epsI
87+ @test parse (Float64, conductor_node[" Cext" ]) ≈ expected_Cext
88+ @test parse (Float64, conductor_node[" Gext" ]) ≈ expected_Gext
89+ end
90+ end
91+ @info " All detailed checks passed!"
92+ end
93+ end
94+
95+
96+
97+
98+ @testitem " ImportExport(export_data::atp): export LineParameters -> ZY matrices" setup = [defaults, cable_system_export, deps_export_atp] begin
99+
100+
101+
102+ # 1. RUN THE TEST IN A TEMPORARY DIRECTORY
103+ mktempdir (joinpath (@__DIR__ )) do tmpdir
104+ output_file = joinpath (tmpdir, " atp_export_test.xml" )
105+ @info " Exporting ATP XML file to: $output_file "
106+ Z_matrix = randn (ComplexF64, num_phases, num_phases, length (freqs))
107+ Y_matrix = randn (ComplexF64, num_phases, num_phases, length (freqs))
108+ line_params = LineParameters (Z_matrix, Y_matrix)
109+
110+ # Call the function we want to test (use the LineParameters overload and pass freqs)
111+ result_path = export_data (:atp , line_params, freqs; file_name= output_file, cable_system= cable_system)
112+ expected_file = joinpath (dirname (output_file), " $(cable_system. system_id) _$(basename (output_file)) " )
113+
114+ # 2. BASIC FILE CHECKS
115+ @test result_path == expected_file
116+ @test isfile (expected_file)
117+ @test filesize (expected_file) > 100
118+
119+ xml_content = read (expected_file, String)
120+ @test occursin (" <ZY" , xml_content)
121+ @test occursin (" </ZY>" , xml_content)
122+
123+ # 3. XML STRUCTURE AND DATA VALIDATION
124+ @info " Performing XML structure checks via XPath..."
125+ xml_doc = readxml (expected_file)
126+ root_node = root (xml_doc)
127+
128+ @test nodename (root_node) == " ZY"
129+ @test parse (Int, root_node[" NumPhases" ]) == num_phases
130+
131+ # Search the whole document for Z blocks (safer) and assert presence before indexing
132+ z_blocks = findall (" //Z" , xml_doc)
133+ @test ! isempty (z_blocks)
134+ @test length (z_blocks) == length (freqs)
135+
136+ # 4. DETAILED DATA VERIFICATION (for the first frequency)
137+ @info " Verifying numerical data for first frequency..."
138+ first_z_block = z_blocks[1 ]
139+ @test parse (Float64, first_z_block[" Freq" ]) ≈ freqs[1 ]
140+
141+ z_matrix_rows = split (strip (nodecontent (first_z_block)), ' \n ' )
142+ @test length (z_matrix_rows) == num_phases
143+
144+ first_row_elements = split (z_matrix_rows[1 ], ' ,' )
145+ @test length (first_row_elements) == num_phases
146+ number_pattern = r" (-?[\d\. ]+E[+-]\d +)"
147+ complex_pattern = Regex (" $(number_pattern. pattern) ([+-][\\ d\\ .]+E[+-]\\ d+)i" )
148+
149+ match_result = match (complex_pattern, first_row_elements[1 ])
150+
151+ if ! isnothing (match_result)
152+ # The captures are now guaranteed to be valid Float64 strings
153+ real_part = parse (Float64, match_result. captures[1 ])
154+ imag_part = parse (Float64, match_result. captures[2 ])
155+ parsed_z11 = complex (real_part, imag_part)
156+
157+ expected_z11 = Z_matrix[1 , 1 , 1 ]
158+ @test parsed_z11 ≈ expected_z11 rtol = 1e-12
159+ end
160+ end
161+ end
0 commit comments