Rust · 6089 bytes Raw Blame History
1 use std::path::{Path, PathBuf};
2 use std::process::Command;
3 use std::sync::atomic::{AtomicUsize, Ordering};
4
5 static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
6
7 fn compiler(name: &str) -> PathBuf {
8 if let Some(path) = std::env::var_os(format!("CARGO_BIN_EXE_{}", name)) {
9 return PathBuf::from(path);
10 }
11 let candidate = PathBuf::from("target/debug").join(name);
12 if candidate.exists() {
13 return std::fs::canonicalize(candidate).expect("cannot canonicalize debug compiler path");
14 }
15 let candidate = PathBuf::from("target/release").join(name);
16 if candidate.exists() {
17 return std::fs::canonicalize(candidate)
18 .expect("cannot canonicalize release compiler path");
19 }
20 panic!(
21 "compiler binary '{}' not built — run `cargo build --bins` first",
22 name
23 );
24 }
25
26 fn unique_path(stem: &str, ext: &str) -> PathBuf {
27 let pid = std::process::id();
28 let id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed);
29 std::env::temp_dir().join(format!("afs_alloc_ctor_{}_{}_{}.{}", stem, pid, id, ext))
30 }
31
32 fn unique_dir(stem: &str) -> PathBuf {
33 let dir = unique_path(stem, "dir");
34 std::fs::create_dir_all(&dir).expect("cannot create allocate-constructor test directory");
35 dir
36 }
37
38 fn write_program_in(dir: &Path, name: &str, text: &str) -> PathBuf {
39 let path = dir.join(name);
40 std::fs::write(&path, text).expect("cannot write allocate-constructor test source");
41 path
42 }
43
44 fn compile_program(source: &Path, output: &Path) -> std::process::Output {
45 Command::new(compiler("armfortas"))
46 .args([source.to_str().unwrap(), "-o", output.to_str().unwrap()])
47 .output()
48 .expect("failed to spawn armfortas compile")
49 }
50
51 #[test]
52 fn allocate_source_array_constructor_infers_shape_and_copies_values() {
53 let dir = unique_dir("source_array_ctor");
54 let src = write_program_in(
55 &dir,
56 "main.f90",
57 "program p\n implicit none\n integer, allocatable :: a(:)\n allocate(a, source=[1, 2, 3])\n if (.not. allocated(a)) error stop 1\n if (size(a) /= 3) error stop 2\n if (a(1) /= 1 .or. a(2) /= 2 .or. a(3) /= 3) error stop 3\n print *, size(a)\n print *, a(1), a(2), a(3)\nend program\n",
58 );
59 let exe = dir.join("source_array_ctor.bin");
60 let compile = compile_program(&src, &exe);
61 assert!(
62 compile.status.success(),
63 "compile failed:\nstdout:\n{}\nstderr:\n{}",
64 String::from_utf8_lossy(&compile.stdout),
65 String::from_utf8_lossy(&compile.stderr)
66 );
67
68 let run = Command::new(&exe)
69 .output()
70 .expect("source array constructor runtime failed");
71 assert!(
72 run.status.success(),
73 "source array constructor runtime failed: status={:?}\nstdout:\n{}\nstderr:\n{}",
74 run.status,
75 String::from_utf8_lossy(&run.stdout),
76 String::from_utf8_lossy(&run.stderr)
77 );
78 let stdout = String::from_utf8_lossy(&run.stdout);
79 assert!(
80 stdout.contains("3")
81 && stdout.contains("1")
82 && stdout.contains("2")
83 && stdout.contains("3"),
84 "unexpected source array constructor output: {}",
85 stdout
86 );
87
88 let _ = std::fs::remove_dir_all(&dir);
89 }
90
91 #[test]
92 fn allocate_mold_array_constructor_infers_shape() {
93 let dir = unique_dir("mold_array_ctor");
94 let src = write_program_in(
95 &dir,
96 "main.f90",
97 "program p\n implicit none\n integer, allocatable :: a(:)\n allocate(a, mold=[1, 2, 3])\n if (.not. allocated(a)) error stop 1\n if (size(a) /= 3) error stop 2\n print *, size(a)\nend program\n",
98 );
99 let exe = dir.join("mold_array_ctor.bin");
100 let compile = compile_program(&src, &exe);
101 assert!(
102 compile.status.success(),
103 "compile failed:\nstdout:\n{}\nstderr:\n{}",
104 String::from_utf8_lossy(&compile.stdout),
105 String::from_utf8_lossy(&compile.stderr)
106 );
107
108 let run = Command::new(&exe)
109 .output()
110 .expect("mold array constructor runtime failed");
111 assert!(
112 run.status.success(),
113 "mold array constructor runtime failed: status={:?}\nstdout:\n{}\nstderr:\n{}",
114 run.status,
115 String::from_utf8_lossy(&run.stdout),
116 String::from_utf8_lossy(&run.stderr)
117 );
118 let stdout = String::from_utf8_lossy(&run.stdout);
119 assert!(
120 stdout.contains("3"),
121 "unexpected mold array constructor output: {}",
122 stdout
123 );
124
125 let _ = std::fs::remove_dir_all(&dir);
126 }
127
128 #[test]
129 fn allocate_component_source_array_constructor_infers_shape_and_copies_values() {
130 let dir = unique_dir("component_source_array_ctor");
131 let src = write_program_in(
132 &dir,
133 "main.f90",
134 "program p\n implicit none\n type :: box_t\n integer, allocatable :: vals(:)\n end type box_t\n type(box_t) :: box\n allocate(box%vals, source=[4, 5])\n if (.not. allocated(box%vals)) error stop 1\n if (size(box%vals) /= 2) error stop 2\n if (box%vals(1) /= 4 .or. box%vals(2) /= 5) error stop 3\n print *, size(box%vals)\n print *, box%vals(1), box%vals(2)\nend program\n",
135 );
136 let exe = dir.join("component_source_array_ctor.bin");
137 let compile = compile_program(&src, &exe);
138 assert!(
139 compile.status.success(),
140 "compile failed:\nstdout:\n{}\nstderr:\n{}",
141 String::from_utf8_lossy(&compile.stdout),
142 String::from_utf8_lossy(&compile.stderr)
143 );
144
145 let run = Command::new(&exe)
146 .output()
147 .expect("component source array constructor runtime failed");
148 assert!(
149 run.status.success(),
150 "component source array constructor runtime failed: status={:?}\nstdout:\n{}\nstderr:\n{}",
151 run.status,
152 String::from_utf8_lossy(&run.stdout),
153 String::from_utf8_lossy(&run.stderr)
154 );
155 let stdout = String::from_utf8_lossy(&run.stdout);
156 assert!(
157 stdout.contains("2") && stdout.contains("4") && stdout.contains("5"),
158 "unexpected component source array constructor output: {}",
159 stdout
160 );
161
162 let _ = std::fs::remove_dir_all(&dir);
163 }
164