Skip to main content

test_with_derive/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro_error2::abort_call_site;
3use proc_macro_error2::proc_macro_error;
4use syn::{parse_macro_input, ItemFn, ItemMod};
5
6#[cfg(feature = "runtime")]
7use syn::ReturnType;
8
9use crate::utils::{fn_macro, is_module, lock_macro, mod_macro};
10
11mod env;
12#[cfg(feature = "executable")]
13mod executable;
14mod file;
15#[cfg(feature = "http")]
16mod http;
17#[cfg(feature = "icmp")]
18mod icmp;
19#[cfg(feature = "resource")]
20mod resource;
21#[cfg(feature = "runtime")]
22mod runtime;
23mod socket;
24#[cfg(feature = "timezone")]
25mod timezone;
26#[cfg(feature = "user")]
27mod user;
28mod utils;
29
30/// Run test case when the environment variable is set.
31/// ```
32/// #[cfg(test)]
33/// mod tests {
34///
35///     // PWD environment variable exists
36///     #[test_with::env(PWD)]
37///     #[test]
38///     fn test_works() {
39///         assert!(true);
40///     }
41///
42///     // NOTHING environment variable does not exist
43///     #[test_with::env(NOTHING)]
44///     #[test]
45///     fn test_ignored() {
46///         panic!("should be ignored")
47///     }
48///
49///     // NOT_SAYING environment variable does not exist
50///     #[test_with::env(PWD, NOT_SAYING)]
51///     #[test]
52///     fn test_ignored_too() {
53///         panic!("should be ignored")
54///     }
55/// }
56/// ```
57/// or run all test cases for test module when the environment variable is set.
58/// ```
59/// #[test_with::env(PWD)]
60/// #[cfg(test)]
61/// mod tests {
62///
63///     #[test]
64///     fn test_works() {
65///         assert!(true);
66///     }
67/// }
68/// ```
69#[proc_macro_attribute]
70#[proc_macro_error]
71pub fn env(attr: TokenStream, stream: TokenStream) -> TokenStream {
72    if is_module(&stream) {
73        mod_macro(
74            attr,
75            parse_macro_input!(stream as ItemMod),
76            env::check_env_condition,
77        )
78    } else {
79        fn_macro(
80            attr,
81            parse_macro_input!(stream as ItemFn),
82            env::check_env_condition,
83        )
84    }
85}
86
87/// Run test case when the example running and the environment variable is set.
88///```rust
89/// // write as example in examples/*rs
90/// test_with::runner!(env);
91/// #[test_with::module]
92/// mod env {
93/// #[test_with::runtime_env(PWD)]
94/// fn test_works() {
95///     assert!(true);
96///     }
97/// }
98///```
99#[cfg(not(feature = "runtime"))]
100#[proc_macro_attribute]
101#[proc_macro_error]
102pub fn runtime_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
103    panic!("should be used with runtime feature")
104}
105#[cfg(feature = "runtime")]
106#[proc_macro_attribute]
107#[proc_macro_error]
108pub fn runtime_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
109    env::runtime_env(attr, stream)
110}
111
112/// Ignore test case when the environment variable is set.
113/// ```
114/// #[cfg(test)]
115/// mod tests {
116///
117///     // The test will be ignored in GITHUB_ACTION
118///     #[test_with::no_env(GITHUB_ACTIONS)]
119///     #[test]
120///     fn test_ignore_in_github_action() {
121///         assert!(false);
122///     }
123/// }
124#[proc_macro_attribute]
125#[proc_macro_error]
126pub fn no_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
127    if is_module(&stream) {
128        mod_macro(
129            attr,
130            parse_macro_input!(stream as ItemMod),
131            env::check_no_env_condition,
132        )
133    } else {
134        fn_macro(
135            attr,
136            parse_macro_input!(stream as ItemFn),
137            env::check_no_env_condition,
138        )
139    }
140}
141
142/// Ignore test case when the example running and the environment variable is set.
143///```rust
144/// // write as example in examples/*rs
145/// test_with::runner!(env);
146/// #[test_with::module]
147/// mod env {
148/// #[test_with::runtime_no_env(NOT_EXIST)]
149/// fn test_works() {
150///     assert!(true);
151///     }
152/// }
153///```
154#[cfg(not(feature = "runtime"))]
155#[proc_macro_attribute]
156#[proc_macro_error]
157pub fn runtime_no_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
158    panic!("should be used with runtime feature")
159}
160#[cfg(feature = "runtime")]
161#[proc_macro_attribute]
162#[proc_macro_error]
163pub fn runtime_no_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
164    env::runtime_no_env(attr, stream)
165}
166
167/// Run test case when the file exist.
168/// ```
169/// #[cfg(test)]
170/// mod tests {
171///
172///     // hostname exists
173///     #[test_with::file(/etc/hostname)]
174///     #[test]
175///     fn test_works() {
176///         assert!(true);
177///     }
178///
179///     // nothing file does not exist
180///     #[test_with::file(/etc/nothing)]
181///     #[test]
182///     fn test_ignored() {
183///         panic!("should be ignored")
184///     }
185///
186///     // hostname and hosts exist
187///     #[test_with::file(/etc/hostname, /etc/hosts)]
188///     #[test]
189///     fn test_works_too() {
190///         assert!(true);
191///     }
192/// }
193/// ```
194#[proc_macro_attribute]
195#[proc_macro_error]
196pub fn file(attr: TokenStream, stream: TokenStream) -> TokenStream {
197    if is_module(&stream) {
198        mod_macro(
199            attr,
200            parse_macro_input!(stream as ItemMod),
201            file::check_file_condition,
202        )
203    } else {
204        fn_macro(
205            attr,
206            parse_macro_input!(stream as ItemFn),
207            file::check_file_condition,
208        )
209    }
210}
211
212/// Run test case when the example running and the file exist.
213///```rust
214/// // write as example in examples/*rs
215/// test_with::runner!(file);
216/// #[test_with::module]
217/// mod file {
218///     #[test_with::runtime_file(/etc/hostname)]
219///     fn test_works() {
220///         assert!(true);
221///     }
222/// }
223///```
224#[cfg(not(feature = "runtime"))]
225#[proc_macro_attribute]
226#[proc_macro_error]
227pub fn runtime_file(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
228    panic!("should be used with runtime feature")
229}
230#[cfg(feature = "runtime")]
231#[proc_macro_attribute]
232#[proc_macro_error]
233pub fn runtime_file(attr: TokenStream, stream: TokenStream) -> TokenStream {
234    file::runtime_file(attr, stream)
235}
236
237/// Run test case when the path(file or folder) exist.
238/// ```
239/// #[cfg(test)]
240/// mod tests {
241///
242///     // etc exists
243///     #[test_with::path(/etc)]
244///     #[test]
245///     fn test_works() {
246///         assert!(true);
247///     }
248///
249///     // nothing does not exist
250///     #[test_with::path(/nothing)]
251///     #[test]
252///     fn test_ignored() {
253///         panic!("should be ignored")
254///     }
255///
256///     // etc and tmp exist
257///     #[test_with::path(/etc, /tmp)]
258///     #[test]
259///     fn test_works_too() {
260///         assert!(true);
261///     }
262/// }
263/// ```
264#[proc_macro_attribute]
265#[proc_macro_error]
266pub fn path(attr: TokenStream, stream: TokenStream) -> TokenStream {
267    if is_module(&stream) {
268        mod_macro(
269            attr,
270            parse_macro_input!(stream as ItemMod),
271            file::check_path_condition,
272        )
273    } else {
274        fn_macro(
275            attr,
276            parse_macro_input!(stream as ItemFn),
277            file::check_path_condition,
278        )
279    }
280}
281
282/// Run test case when the example running and the path(file or folder) exist.
283///```rust
284/// // write as example in examples/*rs
285/// test_with::runner!(path);
286/// #[test_with::module]
287/// mod path {
288///     #[test_with::runtime_path(/etc)]
289///     fn test_works() {
290///         assert!(true);
291///     }
292/// }
293///```
294#[cfg(not(feature = "runtime"))]
295#[proc_macro_attribute]
296#[proc_macro_error]
297pub fn runtime_path(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
298    panic!("should be used with runtime feature")
299}
300#[cfg(feature = "runtime")]
301#[proc_macro_attribute]
302#[proc_macro_error]
303pub fn runtime_path(attr: TokenStream, stream: TokenStream) -> TokenStream {
304    file::runtime_path(attr, stream)
305}
306
307/// Run test case when the http service exist.
308/// ```
309/// #[cfg(test)]
310/// mod tests {
311///
312///     // http service exists
313///     #[test_with::http(httpbin.org)]
314///     #[test]
315///     fn test_works() {
316///         assert!(true);
317///     }
318///
319///     // There is no not.exist.com
320///     #[test_with::http(not.exist.com)]
321///     #[test]
322///     fn test_ignored() {
323///         panic!("should be ignored")
324///     }
325/// }
326/// ```
327#[proc_macro_attribute]
328#[proc_macro_error]
329#[cfg(feature = "http")]
330pub fn http(attr: TokenStream, stream: TokenStream) -> TokenStream {
331    if is_module(&stream) {
332        mod_macro(
333            attr,
334            parse_macro_input!(stream as ItemMod),
335            http::check_http_condition,
336        )
337    } else {
338        fn_macro(
339            attr,
340            parse_macro_input!(stream as ItemFn),
341            http::check_http_condition,
342        )
343    }
344}
345
346/// Run test case when the example running and the http service exist.
347///```rust
348/// // write as example in examples/*rs
349/// test_with::runner!(http);
350/// #[test_with::module]
351/// mod http {
352///     #[test_with::runtime_http(httpbin.org)]
353///     fn test_works() {
354///         assert!(true);
355///     }
356/// }
357#[cfg(not(feature = "runtime"))]
358#[proc_macro_attribute]
359#[proc_macro_error]
360pub fn runtime_http(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
361    panic!("should be used with runtime feature")
362}
363
364#[cfg(all(feature = "runtime", feature = "http"))]
365#[proc_macro_attribute]
366#[proc_macro_error]
367pub fn runtime_http(attr: TokenStream, stream: TokenStream) -> TokenStream {
368    http::runtime_http(attr, stream)
369}
370
371/// Run test case when the https service exist.
372/// ```
373/// #[cfg(test)]
374/// mod tests {
375///
376///     // https server exists
377///     #[test_with::https(www.rust-lang.org)]
378///     #[test]
379///     fn test_works() {
380///         assert!(true);
381///     }
382///
383///     // There is no not.exist.com
384///     #[test_with::https(not.exist.com)]
385///     #[test]
386///     fn test_ignored() {
387///         panic!("should be ignored")
388///     }
389/// }
390/// ```
391#[proc_macro_attribute]
392#[proc_macro_error]
393#[cfg(feature = "http")]
394pub fn https(attr: TokenStream, stream: TokenStream) -> TokenStream {
395    if is_module(&stream) {
396        mod_macro(
397            attr,
398            parse_macro_input!(stream as ItemMod),
399            http::check_https_condition,
400        )
401    } else {
402        fn_macro(
403            attr,
404            parse_macro_input!(stream as ItemFn),
405            http::check_https_condition,
406        )
407    }
408}
409
410/// Run test case when the example running and the http service exist.
411///```rust
412/// // write as example in examples/*rs
413/// test_with::runner!(http);
414/// #[test_with::module]
415/// mod http {
416///     #[test_with::runtime_https(httpbin.org)]
417///     fn test_works() {
418///         assert!(true);
419///     }
420/// }
421#[cfg(all(not(feature = "runtime"), feature = "http"))]
422#[proc_macro_attribute]
423#[proc_macro_error]
424pub fn runtime_https(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
425    panic!("should be used with runtime feature")
426}
427
428#[cfg(all(feature = "runtime", feature = "http"))]
429#[proc_macro_attribute]
430#[proc_macro_error]
431pub fn runtime_https(attr: TokenStream, stream: TokenStream) -> TokenStream {
432    http::runtime_https(attr, stream)
433}
434
435/// Run test case when the server online.
436/// Please make sure the role of test case runner have capability to open socket
437///
438/// ```
439/// #[cfg(test)]
440/// mod tests {
441///
442///     // localhost is online
443///     #[test_with::icmp(127.0.0.1)]
444///     #[test]
445///     fn test_works() {
446///         assert!(true);
447///     }
448///
449///     // 193.194.195.196 is offline
450///     #[test_with::icmp(193.194.195.196)]
451///     #[test]
452///     fn test_ignored() {
453///         panic!("should be ignored")
454///     }
455/// }
456/// ```
457#[proc_macro_attribute]
458#[proc_macro_error]
459#[cfg(feature = "icmp")]
460pub fn icmp(attr: TokenStream, stream: TokenStream) -> TokenStream {
461    if is_module(&stream) {
462        mod_macro(
463            attr,
464            parse_macro_input!(stream as ItemMod),
465            icmp::check_icmp_condition,
466        )
467    } else {
468        fn_macro(
469            attr,
470            parse_macro_input!(stream as ItemFn),
471            icmp::check_icmp_condition,
472        )
473    }
474}
475
476/// Run test case when the example running and the server online.
477/// Please make sure the role of test case runner have capability to open socket
478///```rust
479/// // write as example in examples/*rs
480/// test_with::runner!(icmp);
481/// #[test_with::module]
482/// mod icmp {
483///     // 193.194.195.196 is offline
484///     #[test_with::runtime_icmp(193.194.195.196)]
485///     fn test_ignored_with_non_existing_host() {
486///         panic!("should be ignored with non existing host")
487///     }
488/// }
489#[cfg(all(not(feature = "runtime"), feature = "icmp"))]
490#[proc_macro_attribute]
491#[proc_macro_error]
492pub fn runtime_icmp(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
493    panic!("should be used with runtime feature")
494}
495
496#[cfg(all(feature = "runtime", feature = "icmp"))]
497#[proc_macro_attribute]
498#[proc_macro_error]
499pub fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStream {
500    icmp::runtime_icmp(attr, stream)
501}
502
503/// Run test case when socket connected
504///
505/// ```
506/// #[cfg(test)]
507/// mod tests {
508///
509///     // Google DNS is online
510///     #[test_with::tcp(8.8.8.8:53)]
511///     #[test]
512///     fn test_works() {
513///         assert!(true);
514///     }
515///
516///     // 193.194.195.196 is offline
517///     #[test_with::tcp(193.194.195.196)]
518///     #[test]
519///     fn test_ignored() {
520///         panic!("should be ignored")
521///     }
522/// }
523/// ```
524#[proc_macro_attribute]
525#[proc_macro_error]
526pub fn tcp(attr: TokenStream, stream: TokenStream) -> TokenStream {
527    if is_module(&stream) {
528        mod_macro(
529            attr,
530            parse_macro_input!(stream as ItemMod),
531            socket::check_tcp_condition,
532        )
533    } else {
534        fn_macro(
535            attr,
536            parse_macro_input!(stream as ItemFn),
537            socket::check_tcp_condition,
538        )
539    }
540}
541
542/// Run test case when the example running and socket connected
543///```rust
544/// // write as example in examples/*rs
545/// test_with::runner!(tcp);
546/// #[test_with::module]
547/// mod tcp {
548///     // Google DNS is online
549///     #[test_with::runtime_tcp(8.8.8.8:53)]
550///     fn test_works_with_DNS_server() {
551///         assert!(true);
552///     }
553/// }
554#[cfg(not(feature = "runtime"))]
555#[proc_macro_attribute]
556#[proc_macro_error]
557pub fn runtime_tcp(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
558    panic!("should be used with runtime feature")
559}
560
561#[cfg(feature = "runtime")]
562#[proc_macro_attribute]
563#[proc_macro_error]
564pub fn runtime_tcp(attr: TokenStream, stream: TokenStream) -> TokenStream {
565    socket::runtime_tcp(attr, stream)
566}
567
568/// Run test case when runner is root
569///
570/// ```
571/// #[cfg(test)]
572/// mod tests {
573///
574///     // Only works with root account
575///     #[test_with::root()]
576///     #[test]
577///     fn test_ignored() {
578///         panic!("should be ignored")
579///     }
580/// }
581/// ```
582#[proc_macro_attribute]
583#[proc_macro_error]
584#[cfg(all(feature = "user"))]
585pub fn root(attr: TokenStream, stream: TokenStream) -> TokenStream {
586    if is_module(&stream) {
587        mod_macro(
588            attr,
589            parse_macro_input!(stream as ItemMod),
590            user::check_root_condition,
591        )
592    } else {
593        fn_macro(
594            attr,
595            parse_macro_input!(stream as ItemFn),
596            user::check_root_condition,
597        )
598    }
599}
600
601/// Run test case when runner is root
602///```rust
603/// // write as example in examples/*rs
604/// test_with::runner!(user);
605/// #[test_with::module]
606/// mod user {
607///     // Google DNS is online
608///     #[test_with::runtime_root()]
609///     fn test_ignored() {
610///         panic!("should be ignored")
611///     }
612/// }
613#[cfg(not(feature = "runtime"))]
614#[proc_macro_attribute]
615#[proc_macro_error]
616pub fn runtime_root(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
617    panic!("should be used with runtime feature")
618}
619#[cfg(all(feature = "runtime", feature = "user"))]
620#[proc_macro_attribute]
621#[proc_macro_error]
622pub fn runtime_root(attr: TokenStream, stream: TokenStream) -> TokenStream {
623    user::runtime_root(attr, stream)
624}
625
626/// Run test case when runner in group
627///
628/// ```
629/// #[cfg(test)]
630/// mod tests {
631///
632///     // Only works with group avengers
633///     #[test_with::group(avengers)]
634///     #[test]
635///     fn test_ignored() {
636///         panic!("should be ignored")
637///     }
638/// }
639/// ```
640#[proc_macro_attribute]
641#[proc_macro_error]
642#[cfg(all(feature = "user"))]
643pub fn group(attr: TokenStream, stream: TokenStream) -> TokenStream {
644    if is_module(&stream) {
645        mod_macro(
646            attr,
647            parse_macro_input!(stream as ItemMod),
648            user::check_group_condition,
649        )
650    } else {
651        fn_macro(
652            attr,
653            parse_macro_input!(stream as ItemFn),
654            user::check_group_condition,
655        )
656    }
657}
658
659/// Run test case when runner in group
660///```rust
661/// // write as example in examples/*rs
662/// test_with::runner!(user);
663/// #[test_with::module]
664/// mod user {
665///     // Only works with group avengers
666///     #[test_with::runtime_group(avengers)]
667///     fn test_ignored() {
668///         panic!("should be ignored")
669///     }
670/// }
671#[cfg(not(feature = "runtime"))]
672#[proc_macro_attribute]
673#[proc_macro_error]
674pub fn runtime_group(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
675    panic!("should be used with runtime feature")
676}
677#[cfg(all(feature = "runtime", feature = "user"))]
678#[proc_macro_attribute]
679#[proc_macro_error]
680pub fn runtime_group(attr: TokenStream, stream: TokenStream) -> TokenStream {
681    user::runtime_group(attr, stream)
682}
683
684/// Run test case when runner is specific user
685///
686/// ```
687/// #[cfg(test)]
688/// mod tests {
689///
690///     // Only works with user
691///     #[test_with::user(spider)]
692///     #[test]
693///     fn test_ignored() {
694///         panic!("should be ignored")
695///     }
696/// }
697/// ```
698#[proc_macro_attribute]
699#[proc_macro_error]
700#[cfg(all(feature = "user", not(target_os = "windows")))]
701pub fn user(attr: TokenStream, stream: TokenStream) -> TokenStream {
702    if is_module(&stream) {
703        mod_macro(
704            attr,
705            parse_macro_input!(stream as ItemMod),
706            user::check_user_condition,
707        )
708    } else {
709        fn_macro(
710            attr,
711            parse_macro_input!(stream as ItemFn),
712            user::check_user_condition,
713        )
714    }
715}
716
717/// Run test case when runner is specific user
718///```rust
719/// // write as example in examples/*rs
720/// test_with::runner!(user);
721/// #[test_with::module]
722/// mod user {
723///     // Only works with user
724///     #[test_with::runtime_user(spider)]
725///     fn test_ignored() {
726///         panic!("should be ignored")
727///     }
728/// }
729#[cfg(not(feature = "runtime"))]
730#[proc_macro_attribute]
731#[proc_macro_error]
732pub fn runtime_user(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
733    panic!("should be used with runtime feature")
734}
735#[cfg(all(feature = "runtime", feature = "user"))]
736#[proc_macro_attribute]
737#[proc_macro_error]
738pub fn runtime_user(attr: TokenStream, stream: TokenStream) -> TokenStream {
739    user::runtime_user(attr, stream)
740}
741
742/// Run test case when memory size enough
743///
744/// ```
745/// #[cfg(test)]
746/// mod tests {
747///
748///     // Only works with enough memory size
749///     #[test_with::mem(100GB)]
750///     #[test]
751///     fn test_ignored() {
752///         panic!("should be ignored")
753///     }
754/// }
755/// ```
756#[proc_macro_attribute]
757#[proc_macro_error]
758#[cfg(feature = "resource")]
759pub fn mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
760    if is_module(&stream) {
761        mod_macro(
762            attr,
763            parse_macro_input!(stream as ItemMod),
764            resource::check_mem_condition,
765        )
766    } else {
767        fn_macro(
768            attr,
769            parse_macro_input!(stream as ItemFn),
770            resource::check_mem_condition,
771        )
772    }
773}
774
775/// Run test case when the example running and memory size enough
776///```rust
777/// // write as example in examples/*rs
778/// test_with::runner!(resource);
779/// #[test_with::module]
780/// mod resource {
781///     // Only works with enough memory size
782///     #[test_with::runtime_mem(100GB)]
783///     fn test_ignored_mem_not_enough() {
784///         panic!("should be ignored")
785///     }
786/// }
787#[cfg(not(feature = "runtime"))]
788#[proc_macro_attribute]
789#[proc_macro_error]
790pub fn runtime_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
791    panic!("should be used with runtime feature")
792}
793#[cfg(all(feature = "runtime", feature = "resource"))]
794#[proc_macro_attribute]
795#[proc_macro_error]
796pub fn runtime_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
797    resource::runtime_mem(attr, stream)
798}
799
800/// Run test case when the example running and free memory size enough
801///```rust
802/// // write as example in examples/*rs
803/// test_with::runner!(resource);
804/// #[test_with::module]
805/// mod resource {
806///     // Only works with enough free memory size
807///     #[test_with::runtime_free_mem(100GB)]
808///     fn test_ignored_free_mem_not_enough() {
809///         panic!("should be ignored")
810///     }
811/// }
812#[cfg(not(feature = "runtime"))]
813#[proc_macro_attribute]
814#[proc_macro_error]
815pub fn runtime_free_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
816    panic!("should be used with runtime feature")
817}
818#[cfg(all(feature = "runtime", feature = "resource"))]
819#[proc_macro_attribute]
820#[proc_macro_error]
821pub fn runtime_free_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
822    resource::runtime_free_mem(attr, stream)
823}
824
825/// Run test case when the example running and available memory size enough
826///```rust
827/// // write as example in examples/*rs
828/// test_with::runner!(resource);
829/// #[test_with::module]
830/// mod resource {
831///     // Only works with enough available memory size
832///     #[test_with::runtime_available_mem(100GB)]
833///     fn test_ignored_available_mem_not_enough() {
834///         panic!("should be ignored")
835///     }
836/// }
837#[cfg(not(feature = "runtime"))]
838#[proc_macro_attribute]
839#[proc_macro_error]
840pub fn runtime_available_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
841    panic!("should be used with runtime feature")
842}
843#[cfg(all(feature = "runtime", feature = "resource"))]
844#[proc_macro_attribute]
845#[proc_macro_error]
846pub fn runtime_available_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
847    resource::runtime_available_mem(attr, stream)
848}
849
850/// Run test case when swap size enough
851///
852/// ```
853/// #[cfg(test)]
854/// mod tests {
855///
856///     // Only works with enough swap size
857///     #[test_with::swap(100GB)]
858///     #[test]
859///     fn test_ignored() {
860///         panic!("should be ignored")
861///     }
862/// }
863/// ```
864#[proc_macro_attribute]
865#[proc_macro_error]
866#[cfg(feature = "resource")]
867pub fn swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
868    if is_module(&stream) {
869        mod_macro(
870            attr,
871            parse_macro_input!(stream as ItemMod),
872            resource::check_swap_condition,
873        )
874    } else {
875        fn_macro(
876            attr,
877            parse_macro_input!(stream as ItemFn),
878            resource::check_swap_condition,
879        )
880    }
881}
882
883/// Run test case when the example running and swap enough
884///```rust
885/// // write as example in examples/*rs
886/// test_with::runner!(resource);
887/// #[test_with::module]
888/// mod resource {
889///     // Only works with enough swap size
890///     #[test_with::runtime_swap(100GB)]
891///     fn test_ignored_swap_not_enough() {
892///         panic!("should be ignored")
893///     }
894/// }
895#[cfg(not(feature = "runtime"))]
896#[proc_macro_attribute]
897#[proc_macro_error]
898pub fn runtime_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
899    panic!("should be used with runtime feature")
900}
901#[cfg(all(feature = "runtime", feature = "resource"))]
902#[proc_macro_attribute]
903#[proc_macro_error]
904pub fn runtime_swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
905    let swap_limitation_str = attr.to_string().replace(' ', "");
906    if byte_unit::Byte::parse_str(&swap_limitation_str, true).is_err() {
907        abort_call_site!("swap size description is not correct")
908    }
909
910    let ItemFn {
911        attrs,
912        vis,
913        sig,
914        block,
915    } = parse_macro_input!(stream as ItemFn);
916    let syn::Signature { ident, .. } = sig.clone();
917    let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());
918
919    let check_fn = match (&sig.asyncness, &sig.output) {
920        (Some(_), ReturnType::Default) => quote::quote! {
921            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
922                let sys = test_with::sysinfo::System::new_with_specifics(
923                    test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
924                );
925                let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
926                    Ok(b) => b,
927                    Err(_) => panic!("system swap size can not get"),
928                };
929                let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
930                if  swap_size >= swap_size_limitation {
931                    #ident().await;
932                    Ok(test_with::Completion::Completed)
933                } else {
934                    Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
935                }
936            }
937        },
938        (Some(_), ReturnType::Type(_, _)) => quote::quote! {
939            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
940                let sys = test_with::sysinfo::System::new_with_specifics(
941                    test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
942                );
943                let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
944                    Ok(b) => b,
945                    Err(_) => panic!("system swap size can not get"),
946                };
947                let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
948                if  swap_size >= swap_size_limitation {
949                    if let Err(e) = #ident().await {
950                        Err(format!("{e:?}").into())
951                    } else {
952                        Ok(test_with::Completion::Completed)
953                    }
954                } else {
955                    Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
956                }
957            }
958        },
959        (None, _) => quote::quote! {
960            fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
961                let sys = test_with::sysinfo::System::new_with_specifics(
962                    test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
963                );
964                let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
965                    Ok(b) => b,
966                    Err(_) => panic!("system swap size can not get"),
967                };
968                let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
969                if  swap_size >= swap_size_limitation {
970                    #ident();
971                    Ok(test_with::Completion::Completed)
972                } else {
973                    Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
974                }
975            }
976        },
977    };
978
979    quote::quote! {
980        #check_fn
981        #(#attrs)*
982        #vis #sig #block
983    }
984    .into()
985}
986
987/// Run test case when the example running and free swap enough
988///```rust
989/// // write as example in examples/*rs
990/// test_with::runner!(resource);
991/// #[test_with::module]
992/// mod resource {
993///     // Only works with enough free swap size
994///     #[test_with::runtime_free_swap(100GB)]
995///     fn test_ignored_free_swap_not_enough() {
996///         panic!("should be ignored")
997///     }
998/// }
999#[cfg(not(feature = "runtime"))]
1000#[proc_macro_attribute]
1001#[proc_macro_error]
1002pub fn runtime_free_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1003    panic!("should be used with runtime feature")
1004}
1005#[cfg(all(feature = "runtime", feature = "resource"))]
1006#[proc_macro_attribute]
1007#[proc_macro_error]
1008pub fn runtime_free_swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
1009    resource::runtime_free_swap(attr, stream)
1010}
1011
1012/// Run test case when cpu core enough
1013///
1014/// ```
1015/// #[cfg(test)]
1016/// mod tests {
1017///
1018///     // Only works with enough cpu core
1019///     #[test_with::cpu_core(64)]
1020///     #[test]
1021///     fn test_ignored() {
1022///         panic!("should be ignored")
1023///     }
1024/// }
1025/// ```
1026#[proc_macro_attribute]
1027#[proc_macro_error]
1028#[cfg(feature = "resource")]
1029pub fn cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
1030    if is_module(&stream) {
1031        mod_macro(
1032            attr,
1033            parse_macro_input!(stream as ItemMod),
1034            resource::check_cpu_core_condition,
1035        )
1036    } else {
1037        fn_macro(
1038            attr,
1039            parse_macro_input!(stream as ItemFn),
1040            resource::check_cpu_core_condition,
1041        )
1042    }
1043}
1044
1045/// Run test case when cpu core enough
1046///```rust
1047/// // write as example in examples/*rs
1048/// test_with::runner!(resource);
1049/// #[test_with::module]
1050/// mod resource {
1051///     // Only works with enough cpu core
1052///     #[test_with::runtime_cpu_core(32)]
1053///     fn test_ignored_core_not_enough() {
1054///         panic!("should be ignored")
1055///     }
1056/// }
1057#[cfg(not(feature = "runtime"))]
1058#[proc_macro_attribute]
1059#[proc_macro_error]
1060pub fn runtime_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1061    panic!("should be used with runtime feature")
1062}
1063#[cfg(all(feature = "runtime", feature = "resource"))]
1064#[proc_macro_attribute]
1065#[proc_macro_error]
1066pub fn runtime_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
1067    resource::runtime_cpu_core(attr, stream)
1068}
1069
1070/// Run test case when physical cpu core enough
1071///
1072/// ```
1073/// #[cfg(test)]
1074/// mod tests {
1075///
1076///     // Only works with enough cpu core
1077///     #[test_with::phy_core(64)]
1078///     #[test]
1079///     fn test_ignored() {
1080///         panic!("should be ignored")
1081///     }
1082/// }
1083/// ```
1084#[proc_macro_attribute]
1085#[proc_macro_error]
1086#[cfg(feature = "resource")]
1087pub fn phy_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
1088    if is_module(&stream) {
1089        mod_macro(
1090            attr,
1091            parse_macro_input!(stream as ItemMod),
1092            resource::check_cpu_core_condition,
1093        )
1094    } else {
1095        fn_macro(
1096            attr,
1097            parse_macro_input!(stream as ItemFn),
1098            resource::check_phy_core_condition,
1099        )
1100    }
1101}
1102
1103/// Run test case when physical core enough
1104///```rust
1105/// // write as example in examples/*rs
1106/// test_with::runner!(resource);
1107/// #[test_with::module]
1108/// mod resource {
1109///     // Only works with enough physical cpu core
1110///     #[test_with::runtime_phy_cpu_core(32)]
1111///     fn test_ignored_phy_core_not_enough() {
1112///         panic!("should be ignored")
1113///     }
1114/// }
1115#[cfg(not(feature = "runtime"))]
1116#[proc_macro_attribute]
1117#[proc_macro_error]
1118pub fn runtime_phy_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1119    panic!("should be used with runtime feature")
1120}
1121#[cfg(all(feature = "runtime", feature = "resource"))]
1122#[proc_macro_attribute]
1123#[proc_macro_error]
1124pub fn runtime_phy_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
1125    resource::runtime_phy_cpu_core(attr, stream)
1126}
1127
1128/// Run test case when the executables exist.
1129/// ```
1130/// #[cfg(test)]
1131/// mod tests {
1132///     // `pwd` executable command exists
1133///     #[test_with::executable(pwd)]
1134///     #[test]
1135///     fn test_executable() {
1136///         assert!(true);
1137///     }
1138///
1139///     // `/bin/sh` executable exists
1140///     #[test_with::executable(/bin/sh)]
1141///     #[test]
1142///     fn test_executable_with_path() {
1143///         assert!(true);
1144///     }
1145///
1146///     // `non` does not exist
1147///     #[test_with::executable(non)]
1148///     #[test]
1149///     fn test_non_existing_executable() {
1150///         panic!("should be ignored")
1151///     }
1152///
1153///     // `pwd` and `ls` exist
1154///     #[test_with::executable(pwd, ls)]
1155///     #[test]
1156///     fn test_executables_too() {
1157///         assert!(true);
1158///     }
1159///
1160///     // `non` or `ls` exist
1161///     #[test_with::executable(non || ls)]
1162///     #[test]
1163///     fn test_one_of_executables_exist() {
1164///         assert!(true);
1165///     }
1166/// }
1167/// ```
1168#[proc_macro_attribute]
1169#[proc_macro_error]
1170#[cfg(feature = "executable")]
1171pub fn executable(attr: TokenStream, stream: TokenStream) -> TokenStream {
1172    if is_module(&stream) {
1173        mod_macro(
1174            attr,
1175            parse_macro_input!(stream as ItemMod),
1176            executable::check_executable_condition,
1177        )
1178    } else {
1179        fn_macro(
1180            attr,
1181            parse_macro_input!(stream as ItemFn),
1182            executable::check_executable_condition,
1183        )
1184    }
1185}
1186
1187/// Run test case when the executable existing
1188///```rust
1189/// // write as example in examples/*rs
1190/// test_with::runner!(exe);
1191/// #[test_with::module]
1192/// mod exe {
1193///     // `/bin/sh` executable exists
1194///     #[test_with::runtime_executable(/bin/sh)]
1195///     fn test_executable_with_path() {
1196///         assert!(true);
1197///     }
1198/// }
1199#[cfg(not(feature = "runtime"))]
1200#[proc_macro_attribute]
1201#[proc_macro_error]
1202pub fn runtime_executable(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1203    panic!("should be used with runtime feature")
1204}
1205#[cfg(all(feature = "runtime", feature = "executable"))]
1206#[proc_macro_attribute]
1207#[proc_macro_error]
1208pub fn runtime_executable(attr: TokenStream, stream: TokenStream) -> TokenStream {
1209    executable::runtime_executable(attr, stream)
1210}
1211
1212/// Ignore test case when function return some reason
1213/// The function should be `fn() -> Option<String>`
1214/// ```
1215/// test_with::runner!(custom_mod);
1216///
1217/// fn something_happened() -> Option<String> {
1218///     Some("because something happened".to_string())
1219/// }
1220///
1221/// #[test_with::module]
1222/// mod custom_mod {
1223/// #[test_with::runtime_ignore_if(something_happened)]
1224/// fn test_ignored() {
1225///     assert!(false);
1226///     }
1227/// }
1228/// ```
1229#[cfg(not(feature = "runtime"))]
1230#[proc_macro_attribute]
1231#[proc_macro_error]
1232pub fn runtime_ignore_if(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1233    panic!("should be used with runtime feature")
1234}
1235#[cfg(feature = "runtime")]
1236#[proc_macro_attribute]
1237#[proc_macro_error]
1238pub fn runtime_ignore_if(attr: TokenStream, stream: TokenStream) -> TokenStream {
1239    let ignore_function = syn::Ident::new(
1240        &attr.to_string().replace(' ', ""),
1241        proc_macro2::Span::call_site(),
1242    );
1243    let ItemFn {
1244        attrs,
1245        vis,
1246        sig,
1247        block,
1248    } = parse_macro_input!(stream as ItemFn);
1249    let syn::Signature { ident, .. } = sig.clone();
1250    let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());
1251
1252    let check_fn = match (&sig.asyncness, &sig.output) {
1253        (Some(_), ReturnType::Default) => quote::quote! {
1254            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
1255                if let Some(msg) = #ignore_function() {
1256                    Ok(test_with::Completion::ignored_with(msg))
1257                } else {
1258                    #ident().await;
1259                    Ok(test_with::Completion::Completed)
1260                }
1261            }
1262        },
1263        (Some(_), ReturnType::Type(_, _)) => quote::quote! {
1264            async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
1265                if let Some(msg) = #ignore_function() {
1266                    Ok(test_with::Completion::ignored_with(msg))
1267                } else {
1268                    if let Err(e) = #ident().await {
1269                        Err(format!("{e:?}").into())
1270                    } else {
1271                        Ok(test_with::Completion::Completed)
1272                    }
1273                }
1274            }
1275        },
1276        (None, _) => quote::quote! {
1277            fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
1278                if let Some(msg) = #ignore_function() {
1279                    Ok(test_with::Completion::ignored_with(msg))
1280                } else {
1281                    #ident();
1282                    Ok(test_with::Completion::Completed)
1283                }
1284            }
1285        },
1286    };
1287
1288    quote::quote! {
1289        #check_fn
1290        #(#attrs)*
1291        #vis #sig #block
1292    }
1293    .into()
1294}
1295
1296/// Run test case one by one when the lock is acquired
1297/// It will automatically implement a file lock for the test case to prevent it run in the same
1298/// time. Also, you can pass the second parameter to specific the waiting seconds, default will be
1299/// 60 seconds.
1300/// ```
1301/// #[cfg(test)]
1302/// mod tests {
1303///
1304///     // `LOCK` is file based lock to prevent test1 an test2 run at the same time
1305///     #[test_with::lock(LOCK)]
1306///     #[test]
1307///     fn test_1() {
1308///         assert!(true);
1309///     }
1310///
1311///     // `LOCK` is file based lock to prevent test1 an test2 run at the same time
1312///     #[test_with::lock(LOCK)]
1313///     #[test]
1314///     fn test_2() {
1315///         assert!(true);
1316///     }
1317///
1318///     // `ANOTHER_LOCK` is file based lock to prevent test3 an test4 run at the same time with 3 sec
1319///     // waiting time.
1320///     #[test_with::lock(ANOTHER_LOCK, 3)]
1321///     fn test_3() {
1322///         assert!(true);
1323///     }
1324///
1325///     // `ANOTHER_LOCK` is file based lock to prevent test3 an test4 run at the same time with 3 sec
1326///     // waiting time.
1327///     #[test_with::lock(ANOTHER_LOCK, 3)]
1328///     fn test_4() {
1329///         assert!(true);
1330///     }
1331///
1332/// }
1333#[proc_macro_attribute]
1334#[proc_macro_error]
1335pub fn lock(attr: TokenStream, stream: TokenStream) -> TokenStream {
1336    if is_module(&stream) {
1337        abort_call_site!("#[test_with::lock] only works with fn")
1338    } else {
1339        lock_macro(attr, parse_macro_input!(stream as ItemFn))
1340    }
1341}
1342
1343/// Run test case when the timezone is expected.
1344/// ```
1345/// #[cfg(test)]
1346/// mod tests {
1347///
1348///     // 0 means UTC
1349///     #[test_with::timezone(0)]
1350///     #[test]
1351///     fn test_works() {
1352///         assert!(true);
1353///     }
1354///
1355///     // UTC is GMT+0
1356///     #[test_with::timezone(UTC)]
1357///     #[test]
1358///     fn test_works_too() {
1359///         assert!(true);
1360///     }
1361///
1362///     // +8 means GMT+8
1363///     #[test_with::timezone(+8)]
1364///     #[test]
1365///     fn test_ignored() {
1366///         panic!("should be ignored")
1367///     }
1368///
1369///     // HKT GMT+8
1370///     #[test_with::timezone(HKT)]
1371///     #[test]
1372///     fn test_ignored_too() {
1373///         panic!("should be ignored")
1374///     }
1375/// }
1376/// ```
1377#[cfg(feature = "timezone")]
1378#[proc_macro_attribute]
1379#[proc_macro_error]
1380pub fn timezone(attr: TokenStream, stream: TokenStream) -> TokenStream {
1381    if is_module(&stream) {
1382        mod_macro(
1383            attr,
1384            parse_macro_input!(stream as ItemMod),
1385            timezone::check_tz_condition,
1386        )
1387    } else {
1388        fn_macro(
1389            attr,
1390            parse_macro_input!(stream as ItemFn),
1391            timezone::check_tz_condition,
1392        )
1393    }
1394}
1395
1396/// Run test case when the example running within specific timezones.
1397///```rust
1398/// // write as example in examples/*rs
1399/// test_with::runner!(timezone);
1400/// #[test_with::module]
1401/// mod timezone {
1402///     // 0 means UTC timezone
1403///     #[test_with::runtime_timezone(0)]
1404///     fn test_works() {
1405///         assert!(true);
1406///     }
1407/// }
1408#[cfg(not(feature = "runtime"))]
1409#[proc_macro_attribute]
1410#[proc_macro_error]
1411pub fn runtime_timezone(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1412    abort_call_site!("should be used with runtime feature")
1413}
1414
1415#[cfg(all(feature = "runtime", feature = "timezone"))]
1416#[proc_macro_attribute]
1417#[proc_macro_error]
1418pub fn runtime_timezone(attr: TokenStream, stream: TokenStream) -> TokenStream {
1419    timezone::runtime_timezone(attr, stream)
1420}
1421
1422/// Provide a test runner and test on each module
1423///```rust
1424/// // example/run-test.rs
1425///
1426/// test_with::runner!(module1, module2);
1427/// #[test_with::module]
1428/// mod module1 {
1429///     #[test_with::runtime_env(PWD)]
1430///     fn test_works() {
1431///         assert!(true);
1432///     }
1433/// }
1434///
1435/// #[test_with::module]
1436/// mod module2 {
1437///     #[test_with::runtime_env(PWD)]
1438///     fn test_works() {
1439///         assert!(true);
1440///     }
1441/// }
1442///```
1443#[cfg(not(feature = "runtime"))]
1444#[proc_macro]
1445pub fn runner(_input: TokenStream) -> TokenStream {
1446    abort_call_site!("should be used with runtime feature")
1447}
1448#[cfg(feature = "runtime")]
1449#[proc_macro]
1450pub fn runner(input: TokenStream) -> TokenStream {
1451    runtime::runner(input)
1452}
1453
1454#[cfg(not(feature = "runtime"))]
1455#[proc_macro]
1456pub fn tokio_runner(_input: TokenStream) -> TokenStream {
1457    abort_call_site!("should be used with `runtime` feature")
1458}
1459#[cfg(feature = "runtime")]
1460#[proc_macro]
1461pub fn tokio_runner(input: TokenStream) -> TokenStream {
1462    runtime::tokio_runner(input)
1463}
1464
1465/// Help each function with `#[test_with::runtime_*]` in the module can register to run
1466/// Also you can set up a mock instance for all of the test in the module
1467///
1468/// ```rust
1469///  // example/run-test.rs
1470///
1471///  test_with::runner!(module1, module2);
1472///  #[test_with::module]
1473///  mod module1 {
1474///      #[test_with::runtime_env(PWD)]
1475///      fn test_works() {
1476///          assert!(true);
1477///      }
1478///  }
1479///
1480///  #[test_with::module]
1481///  mod module2 {
1482///      #[test_with::runtime_env(PWD)]
1483///      fn test_works() {
1484///          assert!(true);
1485///      }
1486///  }
1487/// ```
1488/// You can set up mock with a public struct named `TestEnv` inside the module, or a public type
1489/// named `TestEnv` inside the module.  And the type or struct should have a Default trait for
1490/// initialize the mock instance.
1491/// ```rust
1492/// use std::ops::Drop;
1493/// use std::process::{Child, Command};
1494///
1495/// test_with::runner!(net);
1496///
1497/// #[test_with::module]
1498/// mod net {
1499///     pub struct TestEnv {
1500///         p: Child,
1501///     }
1502///
1503///     impl Default for TestEnv {
1504///         fn default() -> TestEnv {
1505///             let p = Command::new("python")
1506///                 .args(["-m", "http.server"])
1507///                 .spawn()
1508///                 .expect("failed to execute child");
1509///             let mut count = 0;
1510///             while count < 3 {
1511///                 if test_with::reqwest::blocking::get("http://127.0.0.1:8000").is_ok() {
1512///                     break;
1513///                 }
1514///                 std::thread::sleep(std::time::Duration::from_secs(1));
1515///                 count += 1;
1516///             }
1517///             TestEnv { p }
1518///         }
1519///     }
1520///
1521///     impl Drop for TestEnv {
1522///         fn drop(&mut self) {
1523///             self.p.kill().expect("fail to kill python http.server");
1524///         }
1525///     }
1526///
1527///     #[test_with::runtime_http(127.0.0.1:8000)]
1528///     fn test_with_environment() {
1529///         assert!(true);
1530///     }
1531/// }
1532///
1533/// ```
1534/// or you can write mock struct in other place and just pass by type.
1535/// ```rust
1536/// use std::ops::Drop;
1537/// use std::process::{Child, Command};
1538///
1539/// test_with::runner!(net);
1540///
1541/// pub struct Moc {
1542///     p: Child,
1543/// }
1544///
1545/// impl Default for Moc {
1546///     fn default() -> Moc {
1547///         let p = Command::new("python")
1548///             .args(["-m", "http.server"])
1549///             .spawn()
1550///             .expect("failed to execute child");
1551///         let mut count = 0;
1552///         while count < 3 {
1553///             if test_with::reqwest::blocking::get("http://127.0.0.1:8000").is_ok() {
1554///                 break;
1555///             }
1556///             std::thread::sleep(std::time::Duration::from_secs(1));
1557///             count += 1;
1558///         }
1559///         Moc { p }
1560///     }
1561/// }
1562///
1563/// impl Drop for Moc {
1564///     fn drop(&mut self) {
1565///         self.p.kill().expect("fail to kill python http.server");
1566///     }
1567/// }
1568///
1569/// #[test_with::module]
1570/// mod net {
1571///     pub type TestEnv = super::Moc;
1572///
1573///     #[test_with::runtime_http(127.0.0.1:8000)]
1574///     fn test_with_environment() {
1575///         assert!(true);
1576///     }
1577/// }
1578/// ```
1579#[cfg(not(feature = "runtime"))]
1580#[proc_macro_attribute]
1581#[proc_macro_error]
1582pub fn module(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
1583    panic!("should be used with runtime feature")
1584}
1585#[cfg(feature = "runtime")]
1586#[proc_macro_attribute]
1587#[proc_macro_error]
1588pub fn module(attr: TokenStream, stream: TokenStream) -> TokenStream {
1589    runtime::module(attr, stream)
1590}