microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.3.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_formatter/src/formatter/tests.rs

784lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use expect_test::{expect, Expect};
5use indoc::indoc;
6
7fn check(input: &str, expect: &Expect) {
8 let actual = super::format_str(input);
9 expect.assert_eq(&actual);
10}
11
12// Removing trailing whitespace from lines
13
14#[test]
15fn remove_trailing_spaces() {
16 let extra_spaces = " ";
17 let input = format!(
18 "/// Doc Comment with trailing spaces{extra_spaces}
19 operation Foo() : Unit {{
20 // Comment with trailing spaces{extra_spaces}
21 let x = 3; // In-line comment with trailing spaces{extra_spaces}
22 let y = 4;{extra_spaces}
23 }}
24"
25 );
26
27 check(
28 input.as_str(),
29 &expect![[r#"
30 /// Doc Comment with trailing spaces
31 operation Foo() : Unit {
32 // Comment with trailing spaces
33 let x = 3; // In-line comment with trailing spaces
34 let y = 4;
35 }
36 "#]],
37 );
38}
39
40#[test]
41fn preserve_string_trailing_spaces() {
42 let extra_spaces = " ";
43 let input = format!(
44 "\"Hello{extra_spaces}
45World\""
46 );
47
48 assert!(super::calculate_format_edits(input.as_str()).is_empty());
49}
50
51// Namespace items begin on their own lines
52
53#[test]
54fn namespace_items_begin_on_their_own_lines() {
55 check(
56 "operation Foo() : Unit {} function Bar() : Unit {}",
57 &expect![[r#"
58 operation Foo() : Unit {}
59 function Bar() : Unit {}"#]],
60 );
61}
62
63// Functor specializations begin on their own lines
64
65#[test]
66fn functor_specs_begin_on_their_own_lines() {
67 check(
68 "operation Foo() : Unit { body ... {} adjoint ... {} controlled (c, ...) {} controlled adjoint (c, ...) {} }",
69 &expect![[r#"
70 operation Foo() : Unit {
71 body ... {}
72 adjoint ... {}
73 controlled (c, ...) {}
74 controlled adjoint (c, ...) {}
75 }"#]],
76 );
77}
78
79#[test]
80fn single_space_between_adjoint_controlled_func_spec_keywords() {
81 check(
82 indoc! {"
83 operation Foo() : Unit {
84 body ... {}
85 adjoint ... {}
86 controlled (c, ...) {}
87 controlled adjoint (c, ...) {}
88 }
89 operation Bar() : Unit {
90 body ... {}
91 adjoint ... {}
92 controlled (c, ...) {}
93 adjoint controlled (c, ...) {}
94 }"},
95 &expect![[r#"
96 operation Foo() : Unit {
97 body ... {}
98 adjoint ... {}
99 controlled (c, ...) {}
100 controlled adjoint (c, ...) {}
101 }
102 operation Bar() : Unit {
103 body ... {}
104 adjoint ... {}
105 controlled (c, ...) {}
106 adjoint controlled (c, ...) {}
107 }"#]],
108 );
109}
110
111// Single spaces before generator keywords
112
113#[test]
114fn single_spaces_before_generator_keywords() {
115 check(
116 indoc! {"
117 operation Foo() : Unit {
118 body ... intrinsic
119 adjoint ... invert
120 controlled (c, ...) distribute
121 controlled adjoint (c, ...) auto
122 adjoint ... self
123 }"},
124 &expect![[r#"
125 operation Foo() : Unit {
126 body ... intrinsic
127 adjoint ... invert
128 controlled (c, ...) distribute
129 controlled adjoint (c, ...) auto
130 adjoint ... self
131 }"#]],
132 );
133}
134
135// Single spaces around most binary operators
136
137#[test]
138fn singe_space_around_arithmetic_bin_ops() {
139 // Note that `-` is missing at this time due to it being unsupported for formatting.
140 check(
141 indoc! {"
142 1+2;
143 1 * 2;
144 4 /2;
145 3% 2;
146 2 ^ 3;
147 "},
148 &expect![[r#"
149 1 + 2;
150 1 * 2;
151 4 / 2;
152 3 % 2;
153 2 ^ 3;
154 "#]],
155 );
156}
157
158#[test]
159fn singe_space_around_bit_wise_bin_ops() {
160 check(
161 indoc! {"
162 1&&&2;
163 1 ||| 2;
164 4 ^^^2;
165 3<<< 2;
166 2 >>> 3;
167 "},
168 &expect![[r#"
169 1 &&& 2;
170 1 ||| 2;
171 4 ^^^ 2;
172 3 <<< 2;
173 2 >>> 3;
174 "#]],
175 );
176}
177
178#[test]
179fn singe_space_around_boolean_bin_ops() {
180 check(
181 indoc! {"
182 true and false;
183 true or false;
184 "},
185 &expect![[r#"
186 true and false;
187 true or false;
188 "#]],
189 );
190}
191
192#[test]
193fn singe_space_around_bin_op_equals() {
194 check(
195 indoc! {"
196 let x += y;
197 let x -=y;
198 let x*= y;
199 let x /= y;
200 let x %= y;
201 "},
202 &expect![[r#"
203 let x += y;
204 let x -= y;
205 let x *= y;
206 let x /= y;
207 let x %= y;
208 "#]],
209 );
210}
211
212#[test]
213fn singe_space_around_equals() {
214 check("let x = 3;", &expect!["let x = 3;"]);
215}
216
217#[test]
218fn singe_space_around_colon() {
219 check("let x : Int = 3;", &expect!["let x : Int = 3;"]);
220}
221
222#[test]
223fn singe_space_around_comp_ops() {
224 // Note that `<` and `>` are missing at this time due to them being unsupported for formatting.
225 check(
226 indoc! {"
227 x <=y;
228 x >= y;
229 x == y;
230 x != y;
231 "},
232 &expect![[r#"
233 x <= y;
234 x >= y;
235 x == y;
236 x != y;
237 "#]],
238 );
239}
240
241#[test]
242fn singe_space_around_ternary() {
243 check("x? 3| 4", &expect!["x ? 3 | 4"]);
244}
245
246#[test]
247fn singe_space_around_copy() {
248 check("x w/3 <- 4", &expect!["x w/ 3 <- 4"]);
249}
250
251#[test]
252fn singe_space_around_copy_and_update() {
253 check("x w/=3 <- 4", &expect!["x w/= 3 <- 4"]);
254}
255
256#[test]
257fn singe_space_around_lambda_ops() {
258 check(
259 indoc! {"
260 let x = () -> ();
261 let y = ()=>();
262 "},
263 &expect![[r#"
264 let x = () -> ();
265 let y = () => ();
266 "#]],
267 );
268}
269
270#[test]
271fn singe_space_around_characteristic_expr() {
272 check(
273 "operation Foo() : Unit is Adj+Ctl {}",
274 &expect!["operation Foo() : Unit is Adj + Ctl {}"],
275 );
276}
277
278#[test]
279fn singe_space_around_functors() {
280 check(
281 "Controlled Adjoint Foo()",
282 &expect!["Controlled Adjoint Foo()"],
283 );
284}
285
286#[test]
287fn singe_space_around_as() {
288 check(
289 "open thing as other;",
290 &expect!["open thing as other;"],
291 );
292}
293
294// No space between unary operators and their operand
295
296#[test]
297fn no_space_before_unwrap() {
298 check("let x = foo !;", &expect!["let x = foo!;"]);
299}
300
301#[test]
302fn no_space_after_bit_negation() {
303 check("let x = ~~~ 3;", &expect!["let x = ~~~3;"]);
304}
305
306#[test]
307fn single_space_around_boolean_negation() {
308 check("let x = not 3;", &expect!["let x = not 3;"]);
309}
310
311// No space after open parentheses and brackets and before close parentheses and brackets
312
313#[test]
314fn no_space_for_parentheses() {
315 check("( 12, 13, 14 )", &expect!["(12, 13, 14)"]);
316}
317
318#[test]
319fn no_space_for_brackets() {
320 check("[ 12 + 13 + 14 ]", &expect!["[12 + 13 + 14]"]);
321}
322
323// No space after open string-interpolation argument braces and before close string-interpolation argument braces
324
325#[test]
326fn no_space_for_string_interpolation_argument_braces() {
327 check(
328 r#"let x = $"First { 1 + 1 } Third";"#,
329 &expect![[r#"let x = $"First {1 + 1} Third";"#]],
330 );
331}
332
333// No space before commas or semicolons
334
335#[test]
336fn no_space_before_comma() {
337 check("(12 , 13 , 14)", &expect!["(12, 13, 14)"]);
338}
339
340#[test]
341fn no_space_before_semicolons() {
342 check("let x = 3 ;", &expect!["let x = 3;"]);
343}
344
345// Newline after semicolons
346
347#[test]
348fn newline_after_semicolon() {
349 check(
350 "let x = 3; let y = 2;",
351 &expect![[r#"
352 let x = 3;
353 let y = 2;"#]],
354 );
355}
356
357#[test]
358fn preserve_eol_comment() {
359 let input = indoc! {"let x = 3; // End-of-line Comment
360 let y = 2;
361 "};
362 assert!(super::calculate_format_edits(input).is_empty());
363}
364
365// Newline before declaration keywords
366
367#[test]
368fn newline_before_let() {
369 check(
370 "let x = 3; {} let y = 2;",
371 &expect![[r#"
372 let x = 3;
373 {}
374 let y = 2;"#]],
375 );
376}
377
378#[test]
379fn newline_before_mutable() {
380 check(
381 "mutable x = 3; {} mutable y = 2;",
382 &expect![[r#"
383 mutable x = 3;
384 {}
385 mutable y = 2;"#]],
386 );
387}
388
389#[test]
390fn newline_before_set() {
391 check(
392 "set x = 3; {} set y = 2;",
393 &expect![[r#"
394 set x = 3;
395 {}
396 set y = 2;"#]],
397 );
398}
399
400#[test]
401fn newline_before_use() {
402 check(
403 "use q = Qubit(); {} use w = Qubit();",
404 &expect![[r#"
405 use q = Qubit();
406 {}
407 use w = Qubit();"#]],
408 );
409}
410
411#[test]
412fn newline_before_borrow() {
413 check(
414 "borrow q = Qubit(); {} borrow w = Qubit();",
415 &expect![[r#"
416 borrow q = Qubit();
417 {}
418 borrow w = Qubit();"#]],
419 );
420}
421
422// Single space before control-flow-helper keywords
423
424#[test]
425fn single_space_before_in() {
426 check("for x in 0..2 {}", &expect![[r#"for x in 0..2 {}"#]]);
427}
428
429#[test]
430fn single_space_before_until() {
431 check(
432 "repeat {} until x fixup {}",
433 &expect![[r#"
434 repeat {} until x
435 fixup {}"#]],
436 );
437}
438
439#[test]
440fn single_space_before_elif_and_else() {
441 check(
442 "if x {} elif y {} else {}",
443 &expect!["if x {} elif y {} else {}"],
444 );
445}
446
447#[test]
448fn single_space_before_apply() {
449 check("within {} apply {}", &expect!["within {} apply {}"]);
450}
451
452// No space between caller expressions and argument tuple
453
454#[test]
455fn no_space_in_front_of_argument_tuple() {
456 check("Foo (1, 2, 3)", &expect!["Foo(1, 2, 3)"]);
457}
458
459#[test]
460fn no_space_in_front_of_parameter_tuple() {
461 check(
462 "operation Foo (x : Int, y : Int) : Unit {}",
463 &expect!["operation Foo(x : Int, y : Int) : Unit {}"],
464 );
465}
466
467// No space between array expressions and indexing brackets
468
469#[test]
470fn no_space_in_front_of_array_indexing() {
471 check("arr [4]", &expect!["arr[4]"]);
472}
473
474// No space around `.`, `..`, and `::` operators
475
476#[test]
477fn no_space_around_dot_operator() {
478 check("let x = thing . other;", &expect!["let x = thing.other;"]);
479}
480
481#[test]
482fn no_space_around_range_operator() {
483 check("let x = 1 .. 4;", &expect!["let x = 1..4;"]);
484}
485
486#[test]
487fn no_space_around_field_operator() {
488 check("let x = thing :: other;", &expect!["let x = thing::other;"]);
489}
490
491// No space between the `…` operator and any possible operands on either side
492
493#[test]
494fn no_space_around_full_range_in_slice() {
495 check("let x = y[ ... ];", &expect!["let x = y[...];"]);
496}
497
498#[test]
499fn no_space_between_open_end_range_and_operand() {
500 check("let x = 15 ...;", &expect!["let x = 15...;"]);
501}
502
503#[test]
504fn no_space_between_open_start_range_and_operand() {
505 check("let x = ... 15;", &expect!["let x = ...15;"]);
506}
507
508// Single space before open brace and newline after, except empty blocks have no space
509
510#[test]
511fn single_space_before_open_brace_and_newline_after() {
512 check(
513 indoc! {r#"
514 operation Foo() : Unit{ let x = 3; }
515 operation Bar() : Unit
516 { { let x = 3; }{ let x = 4; } }
517 "#},
518 &expect![[r#"
519 operation Foo() : Unit {
520 let x = 3;
521 }
522 operation Bar() : Unit
523 {
524 {
525 let x = 3;
526 } {
527 let x = 4;
528 }
529 }
530 "#]],
531 );
532}
533
534#[test]
535fn remove_spaces_between_empty_delimiters() {
536 check(
537 indoc! {r#"
538 operation Foo() : Unit {
539 }
540 operation Bar() : Unit {
541 operation Baz() : Unit { }
542 let x = {
543
544 };
545 let y : Int[] = [ ];
546 let z = (
547
548 );
549 }
550 "#},
551 &expect![[r#"
552 operation Foo() : Unit {}
553 operation Bar() : Unit {
554 operation Baz() : Unit {}
555 let x = {};
556 let y : Int[] = [];
557 let z = ();
558 }
559 "#]],
560 );
561}
562
563// Single space before literals
564
565#[test]
566fn single_space_before_literals() {
567 check(
568 indoc! {"
569 let x = 15;
570 let x = 0xF;
571 let x = 15.0;
572 let x = 15L;
573 let x = \"Fifteen\";
574 let x = $\"Fifteen\";
575 let x = PauliI;
576 let x = PauliX;
577 let x = PauliY;
578 let x = PauliZ;
579 let x = true;
580 let x = false;
581 let x = One;
582 let x = Zero;
583 "},
584 &expect![[r#"
585 let x = 15;
586 let x = 0xF;
587 let x = 15.0;
588 let x = 15L;
589 let x = "Fifteen";
590 let x = $"Fifteen";
591 let x = PauliI;
592 let x = PauliX;
593 let x = PauliY;
594 let x = PauliZ;
595 let x = true;
596 let x = false;
597 let x = One;
598 let x = Zero;
599 "#]],
600 );
601}
602
603// Single space before types
604
605#[test]
606fn single_space_before_types() {
607 check(
608 "let x : (Int, Double, String[], (BigInt, Unit), ('T,)) => 'T = foo;",
609 &expect![[r#"let x : (Int, Double, String[], (BigInt, Unit), ('T,)) => 'T = foo;"#]],
610 );
611}
612
613// Single space before variables
614
615#[test]
616fn single_space_before_idents() {
617 check("let x = foo;", &expect!["let x = foo;"]);
618}
619
620// Formatter continues after error token
621
622#[test]
623fn formatter_continues_after_error_token() {
624 check(
625 indoc! {"
626 let x : ' T = foo;
627 let x : ` T = foo;
628 let x : & T = foo;
629 let x : || T = foo;
630 let x : ^^ T = foo;
631 "},
632 &expect![[r#"
633 let x : ' T = foo;
634 let x : ` T = foo;
635 let x : & T = foo;
636 let x : || T = foo;
637 let x : ^^ T = foo;
638 "#]],
639 );
640}
641
642#[test]
643fn formatter_does_not_crash_on_non_terminating_string() {
644 super::calculate_format_edits("let x = \"Hello World");
645}
646
647// Correct indentation, which increases by four spaces when a brace-delimited block is opened and decreases when block is closed
648
649#[test]
650fn formatting_corrects_indentation() {
651 check(
652 r#"
653 /// First
654/// Second
655 /// Third
656 namespace MyQuantumProgram {
657 open Microsoft.Quantum.Diagnostics;
658
659 @EntryPoint()
660 operation Main() : Int {
661 let x = 3;
662 let y = 4;
663
664 // Comment
665 return 5;
666 }
667 }
668"#,
669 &expect![[r#"
670 /// First
671 /// Second
672 /// Third
673 namespace MyQuantumProgram {
674 open Microsoft.Quantum.Diagnostics;
675
676 @EntryPoint()
677 operation Main() : Int {
678 let x = 3;
679 let y = 4;
680
681 // Comment
682 return 5;
683 }
684 }
685 "#]],
686 );
687}
688
689#[test]
690fn preserve_string_indentation() {
691 let input = r#""Hello
692 World""#;
693
694 assert!(super::calculate_format_edits(input).is_empty());
695}
696
697// Will respect user new-lines and indentation added into expressions
698
699#[test]
700fn preserve_user_newlines_in_expressions() {
701 let input = indoc! {r#"
702 let x = [
703 thing1,
704 thing2,
705 thing3,
706 ];
707 let y = 1 + 2 + 3 + 4 + 5 +
708 6 + 7 + 8 + 9 + 10;
709 "#};
710 assert!(super::calculate_format_edits(input).is_empty());
711}
712
713// Remove extra whitespace from start of code
714
715#[test]
716fn remove_extra_whitespace_from_start_of_code() {
717 let input = indoc! {r#"
718
719
720
721
722 namespace Foo {}"#};
723
724 check(input, &expect!["namespace Foo {}"]);
725}
726
727// Extra test cases for sanity
728
729#[test]
730fn preserve_comments_at_start_of_file() {
731 let input = indoc! {r#"
732 // Initial Comment
733 namespace Foo {}"#};
734
735 assert!(super::calculate_format_edits(input).is_empty());
736}
737
738#[test]
739fn sample_has_no_formatting_changes() {
740 let input = indoc! {r#"
741 /// # Sample
742 /// Joint Measurement
743 ///
744 /// # Description
745 /// Joint measurements, also known as Pauli measurements, are a generalization
746 /// of 2-outcome measurements to multiple qubits and other bases.
747 namespace Sample {
748 open Microsoft.Quantum.Diagnostics;
749
750 @EntryPoint()
751 operation Main() : (Result, Result[]) {
752 // Prepare an entangled state.
753 use qs = Qubit[2]; // |00〉
754 H(qs[0]); // 1/sqrt(2)(|00〉 + |10〉)
755 CNOT(qs[0], qs[1]); // 1/sqrt(2)(|00〉 + |11〉)
756
757 // Show the quantum state before performing the joint measurement.
758 DumpMachine();
759
760 // The below code uses a joint measurement as a way to check the parity
761 // of the first two qubits. In this case, the parity measurement result
762 // will always be `Zero`.
763 // Notice how the state was not collapsed by the joint measurement.
764 let parityResult = Measure([PauliZ, PauliZ], qs[...1]);
765 DumpMachine();
766
767 // However, if we perform a measurement just on the first qubit, we can
768 // see how the state collapses.
769 let firstQubitResult = M(qs[0]);
770 DumpMachine();
771
772 // Measuring the last qubit does not change the quantum state
773 // since the state of the second qubit collapsed when the first qubit
774 // was measured because they were entangled.
775 let secondQubitResult = M(qs[1]);
776 DumpMachine();
777
778 ResetAll(qs);
779 return (parityResult, [firstQubitResult, secondQubitResult]);
780 }
781 }
782 "#};
783 assert!(super::calculate_format_edits(input).is_empty());
784}
785