// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. // This is a comprehensive test of invocations with and without // trailing commas (or other, similar optionally-trailing separators). // Every macro is accounted for, even those not tested in this file. // (There will be a note indicating why). // // The expectation is for this to be updated as new macros are added, // or as functionality is added to existing macros. // // (FIXME: (please discuss in PR) is the above expectation reasonable?) // std and core are both tested because they may contain separate // implementations for some macro_rules! macros as an implementation // detail. // compile-flags: --test -C debug_assertions=yes // revisions: std core #![cfg_attr(core, no_std)] #![feature(concat_idents)] #[cfg(std)] use std::fmt; #[cfg(core)] use core::fmt; #[test] fn assert() { assert!(true); assert!(true,); assert!(true, "hello"); assert!(true, "hello",); assert!(true, "hello {}", "world"); assert!(true, "hello {}", "world",); } #[test] fn assert_eq() { assert_eq!(1, 1); assert_eq!(1, 1,); assert_eq!(1, 1, "hello"); assert_eq!(1, 1, "hello",); assert_eq!(1, 1, "hello {}", "world"); assert_eq!(1, 1, "hello {}", "world",); } #[test] fn assert_ne() { assert_ne!(1, 2); assert_ne!(1, 2,); assert_ne!(1, 2, "hello"); assert_ne!(1, 2, "hello",); assert_ne!(1, 2, "hello {}", "world"); assert_ne!(1, 2, "hello {}", "world",); } #[test] fn cfg() { let _ = cfg!(pants); let _ = cfg!(pants,); let _ = cfg!(pants = "pants"); let _ = cfg!(pants = "pants",); let _ = cfg!(all(pants)); let _ = cfg!(all(pants),); let _ = cfg!(all(pants,)); let _ = cfg!(all(pants,),); } #[test] fn column() { let _ = column!(); } // compile_error! is in a companion to this test in compile-fail #[test] fn concat() { let _ = concat!(); let _ = concat!("hello"); let _ = concat!("hello",); let _ = concat!("hello", " world"); let _ = concat!("hello", " world",); } #[test] fn concat_idents() { fn foo() {} fn foobar() {} concat_idents!(foo)(); concat_idents!(foo,)(); concat_idents!(foo, bar)(); concat_idents!(foo, bar,)(); } #[test] fn debug_assert() { debug_assert!(true); debug_assert!(true, ); debug_assert!(true, "hello"); debug_assert!(true, "hello",); debug_assert!(true, "hello {}", "world"); debug_assert!(true, "hello {}", "world",); } #[test] fn debug_assert_eq() { debug_assert_eq!(1, 1); debug_assert_eq!(1, 1,); debug_assert_eq!(1, 1, "hello"); debug_assert_eq!(1, 1, "hello",); debug_assert_eq!(1, 1, "hello {}", "world"); debug_assert_eq!(1, 1, "hello {}", "world",); } #[test] fn debug_assert_ne() { debug_assert_ne!(1, 2); debug_assert_ne!(1, 2,); debug_assert_ne!(1, 2, "hello"); debug_assert_ne!(1, 2, "hello",); debug_assert_ne!(1, 2, "hello {}", "world"); debug_assert_ne!(1, 2, "hello {}", "world",); } #[test] fn env() { let _ = env!("PATH"); let _ = env!("PATH",); let _ = env!("PATH", "not found"); let _ = env!("PATH", "not found",); } #[cfg(std)] #[test] fn eprint() { eprint!("hello"); eprint!("hello",); eprint!("hello {}", "world"); eprint!("hello {}", "world",); } #[cfg(std)] #[test] fn eprintln() { eprintln!(); eprintln!("hello"); eprintln!("hello",); eprintln!("hello {}", "world"); eprintln!("hello {}", "world",); } #[test] fn file() { let _ = file!(); } #[cfg(std)] #[test] fn format() { let _ = format!("hello"); let _ = format!("hello",); let _ = format!("hello {}", "world"); let _ = format!("hello {}", "world",); } #[test] fn format_args() { let _ = format_args!("hello"); let _ = format_args!("hello",); let _ = format_args!("hello {}", "world"); let _ = format_args!("hello {}", "world",); } #[test] fn include() { let _ = include!("auxiliary/macro-comma-support.rs"); let _ = include!("auxiliary/macro-comma-support.rs",); } #[test] fn include_bytes() { let _ = include_bytes!("auxiliary/macro-comma-support.rs"); let _ = include_bytes!("auxiliary/macro-comma-support.rs",); } #[test] fn include_str() { let _ = include_str!("auxiliary/macro-comma-support.rs"); let _ = include_str!("auxiliary/macro-comma-support.rs",); } #[test] fn line() { let _ = line!(); } #[test] fn module_path() { let _ = module_path!(); } #[test] fn option_env() { let _ = option_env!("PATH"); let _ = option_env!("PATH",); } #[test] fn panic() { // prevent 'unreachable code' warnings let falsum = || false; if falsum() { panic!(); } if falsum() { panic!("hello"); } if falsum() { panic!("hello",); } if falsum() { panic!("hello {}", "world"); } if falsum() { panic!("hello {}", "world",); } } #[cfg(std)] #[test] fn print() { print!("hello"); print!("hello",); print!("hello {}", "world"); print!("hello {}", "world",); } #[cfg(std)] #[test] fn println() { println!(); println!("hello"); println!("hello",); println!("hello {}", "world"); println!("hello {}", "world",); } // FIXME: select! (please discuss in PR) // // Test cases for select! are obnoxiously large, see here: // // https://github.com/ExpHP/rust-macro-comma-test/blob/0062e75e01ab/src/main.rs#L190-L250 // // and due to other usability issues described there, it is unclear to me that it is // going anywhere in its current state. This is a job far too big for a macro_rules! macro, // and for as long as it exists in this form it will have many many problems far worse than // just lack of trailing comma support. // stringify! is N/A #[cfg(std)] #[test] fn thread_local() { // this has an optional trailing *semicolon* thread_local! { #[allow(unused)] pub static A: () = () } thread_local! { #[allow(unused)] pub static AA: () = (); } thread_local! { #[allow(unused)] pub static AAA: () = (); #[allow(unused)] pub static AAAA: () = () } thread_local! { #[allow(unused)] pub static AAAAG: () = (); #[allow(unused)] pub static AAAAGH: () = (); } } #[test] fn try() { fn inner() -> Result<(), ()> { try!(Ok(())); try!(Ok(()),); Ok(()) } inner().unwrap(); } #[test] fn unimplemented() { // prevent 'unreachable code' warnings let falsum = || false; if falsum() { unimplemented!(); } if falsum() { unimplemented!("hello"); } if falsum() { unimplemented!("hello",); } if falsum() { unimplemented!("hello {}", "world"); } if falsum() { unimplemented!("hello {}", "world",); } } #[test] fn unreachable() { // prevent 'unreachable code' warnings let falsum = || false; if falsum() { unreachable!(); } if falsum() { unreachable!("hello"); } if falsum() { unreachable!("hello",); } if falsum() { unreachable!("hello {}", "world"); } if falsum() { unreachable!("hello {}", "world",); } } #[cfg(std)] #[test] fn vec() { let _: Vec<()> = vec![]; let _ = vec![0]; let _ = vec![0,]; let _ = vec![0, 1]; let _ = vec![0, 1,]; } // give a test body access to a fmt::Formatter, which seems // to be the easiest way to use 'write!' on core. macro_rules! test_with_formatter { ( #[test] fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block ) => { #[test] fn $fname() { struct Struct; impl fmt::Display for Struct { fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result { Ok($block) } } // suppress "unused" assert!(true, "{}", Struct); } }; } test_with_formatter! { #[test] fn write(f: &mut fmt::Formatter) { let _ = write!(f, "hello"); let _ = write!(f, "hello",); let _ = write!(f, "hello {}", "world"); let _ = write!(f, "hello {}", "world",); } } test_with_formatter! { #[test] fn writeln(f: &mut fmt::Formatter) { let _ = writeln!(f); let _ = writeln!(f,); let _ = writeln!(f, "hello"); let _ = writeln!(f, "hello",); let _ = writeln!(f, "hello {}", "world"); let _ = writeln!(f, "hello {}", "world",); } }