microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/compiler/qsc/src/packages/tests.rs

345lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3use crate::{LanguageFeatures, TargetCapabilityFlags, compile};
4use expect_test::expect;
5use qsc_data_structures::source::SourceMap;
6use qsc_frontend::compile::CompileUnit;
7use qsc_passes::PackageType;
8use qsc_project::{PackageInfo, Project, ProjectType};
9use rustc_hash::FxHashMap;
10use std::sync::Arc;
11
12fn mock_program() -> Project {
13 // Mock data for the ProgramConfig
14 let package_graph_sources = qsc_project::PackageGraphSources {
15 root: qsc_project::PackageInfo {
16 sources: vec![(
17 Arc::from("test.qs"),
18 Arc::from("@EntryPoint() operation Main() : Unit {}"),
19 )],
20 language_features: LanguageFeatures::default(),
21 dependencies: FxHashMap::from_iter(vec![(
22 Arc::from("SomeLibraryAlias"),
23 Arc::from("SomeLibraryKey"),
24 )]),
25 package_type: Some(qsc_project::PackageType::Exe),
26 },
27 packages: FxHashMap::from_iter(vec![(
28 Arc::from("SomeLibraryKey"),
29 PackageInfo {
30 sources: vec![(
31 Arc::from("librarymain"),
32 Arc::from("operation LibraryMain() : Unit {} export LibraryMain;"),
33 )],
34 language_features: LanguageFeatures::default(),
35 dependencies: FxHashMap::default(),
36 package_type: Some(qsc_project::PackageType::Lib),
37 },
38 )]),
39 has_manifest: true,
40 };
41
42 Project {
43 lints: vec![],
44 errors: vec![],
45 path: "project/qsharp.json".into(),
46 name: "project".into(),
47 project_type: qsc_project::ProjectType::QSharp(package_graph_sources),
48 target_profile: Some(qsc_data_structures::target::Profile::Unrestricted),
49 }
50}
51
52#[test]
53fn test_prepare_package_store() {
54 let program = mock_program();
55 let ProjectType::QSharp(package_graph_sources) = program.project_type else {
56 panic!("project should be a Q# project");
57 };
58 let buildable_program =
59 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
60
61 expect![[r"
62 []
63 "]]
64 .assert_debug_eq(&buildable_program.dependency_errors);
65
66 // compile the user code
67 let compiled = compile::compile(
68 &buildable_program.store,
69 &buildable_program.user_code_dependencies[..],
70 SourceMap::new(buildable_program.user_code.sources, None),
71 PackageType::Exe,
72 TargetCapabilityFlags::default(),
73 LanguageFeatures::default(),
74 );
75
76 let CompileUnit {
77 package,
78 ast,
79 errors,
80 ..
81 } = compiled.0;
82
83 expect![[r#"
84 Package:
85 entry expression: Expr 8 [0-0] [Type Unit]: Call:
86 Expr 7 [24-28] [Type Unit]: Var: Item 1 (Package 3)
87 Expr 6 [28-30] [Type Unit]: Unit
88 Item 0 [0-40] (Public):
89 Namespace (Ident 5 [0-40] "test"): Item 1
90 Item 1 [0-40] (Internal):
91 Parent: 0
92 EntryPoint
93 Callable 0 [14-40] (operation):
94 name: Ident 1 [24-28] "Main"
95 input: Pat 2 [28-30] [Type Unit]: Unit
96 output: Unit
97 functors: empty set
98 body: SpecDecl 3 [14-40]: Impl:
99 Block 4 [38-40]: <empty>
100 adj: <none>
101 ctl: <none>
102 ctl-adj: <none>"#]]
103 .assert_eq(&package.to_string());
104 expect![[r#"
105 Package 0:
106 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
107 Item 3 [0-40]:
108 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
109 Expr 6 [11-13]: Unit
110 Callable 7 [14-40] (Operation):
111 name: Ident 8 [24-28] "Main"
112 input: Pat 9 [28-30]: Unit
113 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
114 body: Block: Block 13 [38-40]: <empty>"#]]
115 .assert_eq(&ast.package.to_string());
116 expect![[r"
117 []
118 "]]
119 .assert_debug_eq(&errors);
120}
121
122// if there are inconsequential errors in the dependency compilation process, we don't want to
123// abort compilation. This way, we can still show the user some diagnostics.
124
125#[test]
126fn missing_dependency_doesnt_force_failure() {
127 let program = mock_program();
128 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
129 panic!("project should be a Q# project");
130 };
131 package_graph_sources
132 .root
133 .dependencies
134 .insert("NonExistent".into(), "nonexistent-dep-key".into());
135
136 let buildable_program =
137 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
138
139 expect![[r"
140 []
141 "]]
142 .assert_debug_eq(&buildable_program.dependency_errors);
143
144 // compile the user code
145 let compiled = compile::compile(
146 &buildable_program.store,
147 &buildable_program.user_code_dependencies[..],
148 SourceMap::new(buildable_program.user_code.sources, None),
149 PackageType::Exe,
150 TargetCapabilityFlags::default(),
151 LanguageFeatures::default(),
152 );
153
154 let CompileUnit {
155 package,
156 ast,
157 errors,
158 ..
159 } = compiled.0;
160
161 expect![[r#"
162 Package:
163 entry expression: Expr 8 [0-0] [Type Unit]: Call:
164 Expr 7 [24-28] [Type Unit]: Var: Item 1 (Package 3)
165 Expr 6 [28-30] [Type Unit]: Unit
166 Item 0 [0-40] (Public):
167 Namespace (Ident 5 [0-40] "test"): Item 1
168 Item 1 [0-40] (Internal):
169 Parent: 0
170 EntryPoint
171 Callable 0 [14-40] (operation):
172 name: Ident 1 [24-28] "Main"
173 input: Pat 2 [28-30] [Type Unit]: Unit
174 output: Unit
175 functors: empty set
176 body: SpecDecl 3 [14-40]: Impl:
177 Block 4 [38-40]: <empty>
178 adj: <none>
179 ctl: <none>
180 ctl-adj: <none>"#]]
181 .assert_eq(&package.to_string());
182 expect![[r#"
183 Package 0:
184 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
185 Item 3 [0-40]:
186 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
187 Expr 6 [11-13]: Unit
188 Callable 7 [14-40] (Operation):
189 name: Ident 8 [24-28] "Main"
190 input: Pat 9 [28-30]: Unit
191 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
192 body: Block: Block 13 [38-40]: <empty>"#]]
193 .assert_eq(&ast.package.to_string());
194 expect![[r"
195 []
196 "]]
197 .assert_debug_eq(&errors);
198}
199
200#[allow(clippy::too_many_lines)]
201#[test]
202fn dependency_error() {
203 let program = mock_program();
204 // Inject a syntax error into one of the dependencies
205 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
206 panic!("project should be a Q# project");
207 };
208 package_graph_sources
209 .packages
210 .values_mut()
211 .next()
212 .expect("expected at least one dependency in the mock program")
213 .sources[0]
214 .1 = "broken_syntax".into();
215
216 let buildable_program =
217 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
218
219 expect![[r#"
220 [
221 WithSource {
222 sources: [
223 Source {
224 name: "librarymain",
225 contents: "broken_syntax",
226 offset: 0,
227 },
228 ],
229 error: Frontend(
230 Error(
231 Parse(
232 Error(
233 Token(
234 Eof,
235 Ident,
236 Span {
237 lo: 0,
238 hi: 13,
239 },
240 ),
241 ),
242 ),
243 ),
244 ),
245 },
246 ]
247 "#]]
248 .assert_debug_eq(&buildable_program.dependency_errors);
249
250 // compile the user code
251 let compiled = compile::compile(
252 &buildable_program.store,
253 &buildable_program.user_code_dependencies[..],
254 SourceMap::new(buildable_program.user_code.sources, None),
255 PackageType::Exe,
256 TargetCapabilityFlags::default(),
257 LanguageFeatures::default(),
258 );
259
260 let CompileUnit {
261 package,
262 ast,
263 errors,
264 ..
265 } = compiled.0;
266
267 expect![[r#"
268 Package:
269 entry expression: Expr 8 [0-0] [Type Unit]: Call:
270 Expr 7 [24-28] [Type Unit]: Var: Item 1 (Package 3)
271 Expr 6 [28-30] [Type Unit]: Unit
272 Item 0 [0-40] (Public):
273 Namespace (Ident 5 [0-40] "test"): Item 1
274 Item 1 [0-40] (Internal):
275 Parent: 0
276 EntryPoint
277 Callable 0 [14-40] (operation):
278 name: Ident 1 [24-28] "Main"
279 input: Pat 2 [28-30] [Type Unit]: Unit
280 output: Unit
281 functors: empty set
282 body: SpecDecl 3 [14-40]: Impl:
283 Block 4 [38-40]: <empty>
284 adj: <none>
285 ctl: <none>
286 ctl-adj: <none>"#]]
287 .assert_eq(&package.to_string());
288 expect![[r#"
289 Package 0:
290 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
291 Item 3 [0-40]:
292 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
293 Expr 6 [11-13]: Unit
294 Callable 7 [14-40] (Operation):
295 name: Ident 8 [24-28] "Main"
296 input: Pat 9 [28-30]: Unit
297 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
298 body: Block: Block 13 [38-40]: <empty>"#]]
299 .assert_eq(&ast.package.to_string());
300 expect![[r"
301 []
302 "]]
303 .assert_debug_eq(&errors);
304}
305
306#[allow(clippy::too_many_lines)]
307#[test]
308fn entry_point_profile_in_project_causes_error() {
309 let program = mock_program();
310 // Inject a syntax error into one of the dependencies
311 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
312 panic!("project should be a Q# project");
313 };
314 package_graph_sources
315 .root
316 .sources
317 .iter_mut()
318 .next()
319 .expect("expected at least one source in the mock program")
320 .1 = "@EntryPoint(Base) operation Main() : Unit { }".into();
321
322 let buildable_program =
323 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
324
325 expect![[r#"
326 [
327 WithSource {
328 sources: [
329 Source {
330 name: "test.qs",
331 contents: "@EntryPoint(Base) operation Main() : Unit { }",
332 offset: 0,
333 },
334 ],
335 error: EntryPointProfileInProject(
336 Span {
337 lo: 12,
338 hi: 16,
339 },
340 ),
341 },
342 ]
343 "#]]
344 .assert_debug_eq(&buildable_program.dependency_errors);
345}
346