@@ -228,6 +228,98 @@ defmodule Mix.UtilsTest do
228228 end
229229 end
230230
231+ describe "write_dot_graph!/4" do
232+ test "preserves newlines and other control characters" do
233+ in_tmp ( "dot_newlines" , fn ->
234+ callback = fn node -> { { node , nil } , [ ] } end
235+
236+ Mix.Utils . write_dot_graph! ( "graph.dot" , "graph" , [ "foo \n bar\r \n baz" ] , callback , [ ] )
237+
238+ assert File . read! ( "graph.dot" ) == """
239+ digraph "graph" {
240+ "foo
241+ bar\r
242+ baz"
243+ }
244+ """
245+ end )
246+ end
247+
248+ test "quote and backslash combinations" do
249+ in_tmp ( "dot_complex" , fn ->
250+ callback = fn node -> { { node , nil } , [ ] } end
251+
252+ test_cases = [
253+ # "fo"o" -> "fo\"o"
254+ { "fo\" o" , "fo\\ \" o" } ,
255+ # "fo\"o" -> "fo\\\"o"
256+ { "fo\\ \" o" , "fo\\ \\ \" o" } ,
257+ # "fo\o" -> "fo\o"
258+ { "fo\\ o" , "fo\\ o" } ,
259+ # "fo\\o" -> "fo\\o"
260+ { "fo\\ \\ o" , "fo\\ \\ o" } ,
261+ # "fo\\\o" -> "fo\\\o"
262+ { "fo\\ \\ \\ o" , "fo\\ \\ \\ o" }
263+ ]
264+
265+ Enum . each ( test_cases , fn { input , expected } ->
266+ Mix.Utils . write_dot_graph! ( "graph.dot" , "graph" , [ input ] , callback , [ ] )
267+ content = File . read! ( "graph.dot" )
268+ assert content == "digraph \" graph\" {\n \" #{ expected } \" \n }\n "
269+ end )
270+ end )
271+ end
272+
273+ test "escapes backslash at end of string" do
274+ in_tmp ( "dot_end_backslash" , fn ->
275+ callback = fn node -> { { node , nil } , [ ] } end
276+
277+ test_cases = [
278+ # "fo\" -> "fo\\" (add backslash)
279+ { "fo\\ " , "fo\\ \\ " } ,
280+ # "fo\\" -> "fo\\" (already valid)
281+ { "fo\\ \\ " , "fo\\ \\ " } ,
282+ # "fo\\\" -> "fo\\\\" (add backslash)
283+ { "fo\\ \\ \\ " , "fo\\ \\ \\ \\ " }
284+ ]
285+
286+ Enum . each ( test_cases , fn { input , expected } ->
287+ Mix.Utils . write_dot_graph! ( "graph.dot" , "graph" , [ input ] , callback , [ ] )
288+ content = File . read! ( "graph.dot" )
289+ assert content == "digraph \" graph\" {\n \" #{ expected } \" \n }\n "
290+ end )
291+ end )
292+ end
293+
294+ test "handles empty strings" do
295+ in_tmp ( "dot_empty" , fn ->
296+ callback = fn node -> { { node , nil } , [ ] } end
297+
298+ Mix.Utils . write_dot_graph! ( "graph.dot" , "graph" , [ "" ] , callback , [ ] )
299+
300+ assert File . read! ( "graph.dot" ) == """
301+ digraph "graph" {
302+ ""
303+ }
304+ """
305+ end )
306+ end
307+
308+ test "handles edge labels with escaping" do
309+ in_tmp ( "dot_edge_labels" , fn ->
310+ callback = fn node -> { { node , "edge \" label\" " } , [ ] } end
311+
312+ Mix.Utils . write_dot_graph! ( "graph.dot" , "graph" , [ "node" ] , callback , [ ] )
313+
314+ assert File . read! ( "graph.dot" ) == """
315+ digraph "graph" {
316+ "node" [label="edge \\ "label\\ ""]
317+ }
318+ """
319+ end )
320+ end
321+ end
322+
231323 defp assert_ebin_symlinked_or_copied ( result ) do
232324 case result do
233325 { :ok , paths } ->
0 commit comments