1use std::path::PathBuf;
7use std::time::Duration;
8
9use crate::config::{
10 BufferConfig, EncodingConfig, LineEnding, LoggingConfig, SessionConfig, TimeoutConfig,
11};
12
13#[derive(Debug, Clone)]
15pub struct SessionBuilder {
16 config: SessionConfig,
17}
18
19impl SessionBuilder {
20 #[must_use]
22 pub fn new() -> Self {
23 Self {
24 config: SessionConfig::default(),
25 }
26 }
27
28 #[must_use]
30 pub fn command(mut self, command: impl Into<String>) -> Self {
31 self.config.command = command.into();
32 self
33 }
34
35 #[must_use]
37 pub fn args<I, S>(mut self, args: I) -> Self
38 where
39 I: IntoIterator<Item = S>,
40 S: Into<String>,
41 {
42 self.config.args = args.into_iter().map(Into::into).collect();
43 self
44 }
45
46 #[must_use]
48 pub fn arg(mut self, arg: impl Into<String>) -> Self {
49 self.config.args.push(arg.into());
50 self
51 }
52
53 #[must_use]
55 pub fn envs<I, K, V>(mut self, envs: I) -> Self
56 where
57 I: IntoIterator<Item = (K, V)>,
58 K: Into<String>,
59 V: Into<String>,
60 {
61 self.config.env = envs
62 .into_iter()
63 .map(|(k, v)| (k.into(), v.into()))
64 .collect();
65 self
66 }
67
68 #[must_use]
70 pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
71 self.config.env.insert(key.into(), value.into());
72 self
73 }
74
75 #[must_use]
77 pub fn working_directory(mut self, path: impl Into<PathBuf>) -> Self {
78 self.config.working_dir = Some(path.into());
79 self
80 }
81
82 #[must_use]
84 pub const fn dimensions(mut self, cols: u16, rows: u16) -> Self {
85 self.config.dimensions = (cols, rows);
86 self
87 }
88
89 #[must_use]
91 pub const fn timeout(mut self, timeout: Duration) -> Self {
92 self.config.timeout.default = timeout;
93 self
94 }
95
96 #[must_use]
98 pub const fn timeout_config(mut self, config: TimeoutConfig) -> Self {
99 self.config.timeout = config;
100 self
101 }
102
103 #[must_use]
105 pub const fn buffer_max_size(mut self, max_size: usize) -> Self {
106 self.config.buffer.max_size = max_size;
107 self
108 }
109
110 #[must_use]
112 pub const fn buffer_config(mut self, config: BufferConfig) -> Self {
113 self.config.buffer = config;
114 self
115 }
116
117 #[must_use]
119 pub const fn line_ending(mut self, line_ending: LineEnding) -> Self {
120 self.config.line_ending = line_ending;
121 self
122 }
123
124 #[must_use]
126 pub const fn unix_line_endings(self) -> Self {
127 self.line_ending(LineEnding::Lf)
128 }
129
130 #[must_use]
144 pub const fn windows_line_endings(self) -> Self {
145 self.line_ending(LineEnding::Cr)
146 }
147
148 #[must_use]
150 pub const fn encoding(mut self, config: EncodingConfig) -> Self {
151 self.config.encoding = config;
152 self
153 }
154
155 #[must_use]
157 pub fn logging(mut self, config: LoggingConfig) -> Self {
158 self.config.logging = config;
159 self
160 }
161
162 #[must_use]
164 pub fn log_to_file(mut self, path: impl Into<PathBuf>) -> Self {
165 self.config.logging.log_file = Some(path.into());
166 self
167 }
168
169 #[must_use]
171 pub fn build(self) -> SessionConfig {
172 self.config
173 }
174}
175
176impl Default for SessionBuilder {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182impl From<SessionBuilder> for SessionConfig {
183 fn from(builder: SessionBuilder) -> Self {
184 builder.build()
185 }
186}
187
188pub struct QuickSession;
190
191impl QuickSession {
192 #[must_use]
194 pub fn shell() -> SessionConfig {
195 SessionBuilder::new().command(Self::default_shell()).build()
196 }
197
198 #[must_use]
200 pub fn bash() -> SessionConfig {
201 SessionBuilder::new()
202 .command("/bin/bash")
203 .arg("--norc")
204 .arg("--noprofile")
205 .build()
206 }
207
208 #[must_use]
210 pub fn command(cmd: impl Into<String>) -> SessionConfig {
211 SessionBuilder::new().command(cmd).build()
212 }
213
214 #[must_use]
216 pub fn ssh(host: &str) -> SessionConfig {
217 SessionBuilder::new()
218 .command("ssh")
219 .arg(host)
220 .timeout(Duration::from_secs(30))
221 .build()
222 }
223
224 #[must_use]
226 pub fn ssh_user(user: &str, host: &str) -> SessionConfig {
227 SessionBuilder::new()
228 .command("ssh")
229 .arg(format!("{user}@{host}"))
230 .timeout(Duration::from_secs(30))
231 .build()
232 }
233
234 #[must_use]
236 pub fn telnet(host: &str, port: u16) -> SessionConfig {
237 SessionBuilder::new()
238 .command("telnet")
239 .arg(host)
240 .arg(port.to_string())
241 .timeout(Duration::from_secs(30))
242 .build()
243 }
244
245 #[must_use]
247 pub fn python() -> SessionConfig {
248 SessionBuilder::new()
249 .command(if cfg!(windows) { "python" } else { "python3" })
250 .arg("-i")
251 .build()
252 }
253
254 #[must_use]
258 pub fn cmd() -> SessionConfig {
259 SessionBuilder::new()
260 .command("cmd.exe")
261 .windows_line_endings()
262 .build()
263 }
264
265 #[must_use]
271 pub fn powershell() -> SessionConfig {
272 let command = if cfg!(windows) {
273 "powershell.exe"
274 } else {
275 "pwsh"
276 };
277 SessionBuilder::new()
278 .command(command)
279 .arg("-NoLogo")
280 .arg("-NoProfile")
281 .build()
282 }
283
284 #[must_use]
286 pub fn zsh() -> SessionConfig {
287 SessionBuilder::new()
288 .command("/bin/zsh")
289 .arg("--no-rcs")
290 .build()
291 }
292
293 #[must_use]
295 pub fn fish() -> SessionConfig {
296 SessionBuilder::new()
297 .command("fish")
298 .arg("--no-config")
299 .build()
300 }
301
302 #[must_use]
304 pub fn repl(cmd: impl Into<String>) -> SessionConfig {
305 SessionBuilder::new().command(cmd).build()
306 }
307
308 #[must_use]
310 pub fn node() -> SessionConfig {
311 SessionBuilder::new().command("node").build()
312 }
313
314 #[must_use]
316 pub fn ruby() -> SessionConfig {
317 SessionBuilder::new()
318 .command("irb")
319 .arg("--simple-prompt")
320 .build()
321 }
322
323 #[must_use]
325 pub fn mysql(host: &str, user: &str, database: &str) -> SessionConfig {
326 SessionBuilder::new()
327 .command("mysql")
328 .arg("-h")
329 .arg(host)
330 .arg("-u")
331 .arg(user)
332 .arg(database)
333 .timeout(Duration::from_secs(30))
334 .build()
335 }
336
337 #[must_use]
339 pub fn mysql_password(host: &str, user: &str, database: &str) -> SessionConfig {
340 SessionBuilder::new()
341 .command("mysql")
342 .arg("-h")
343 .arg(host)
344 .arg("-u")
345 .arg(user)
346 .arg("-p")
347 .arg(database)
348 .timeout(Duration::from_secs(30))
349 .build()
350 }
351
352 #[must_use]
354 pub fn psql(host: &str, user: &str, database: &str) -> SessionConfig {
355 SessionBuilder::new()
356 .command("psql")
357 .arg("-h")
358 .arg(host)
359 .arg("-U")
360 .arg(user)
361 .arg(database)
362 .timeout(Duration::from_secs(30))
363 .build()
364 }
365
366 #[must_use]
368 pub fn docker_exec(container: &str) -> SessionConfig {
369 SessionBuilder::new()
370 .command("docker")
371 .arg("exec")
372 .arg("-it")
373 .arg(container)
374 .arg("/bin/sh")
375 .build()
376 }
377
378 #[must_use]
380 pub fn docker_exec_shell(container: &str, shell: &str) -> SessionConfig {
381 SessionBuilder::new()
382 .command("docker")
383 .arg("exec")
384 .arg("-it")
385 .arg(container)
386 .arg(shell)
387 .build()
388 }
389
390 #[must_use]
392 pub fn docker_run(image: &str) -> SessionConfig {
393 SessionBuilder::new()
394 .command("docker")
395 .arg("run")
396 .arg("-it")
397 .arg("--rm")
398 .arg(image)
399 .build()
400 }
401
402 #[must_use]
404 pub fn redis_cli(host: &str) -> SessionConfig {
405 SessionBuilder::new()
406 .command("redis-cli")
407 .arg("-h")
408 .arg(host)
409 .build()
410 }
411
412 #[must_use]
414 pub fn mongosh(uri: &str) -> SessionConfig {
415 SessionBuilder::new()
416 .command("mongosh")
417 .arg(uri)
418 .timeout(Duration::from_secs(30))
419 .build()
420 }
421
422 #[must_use]
424 pub fn sqlite(database: &str) -> SessionConfig {
425 SessionBuilder::new()
426 .command("sqlite3")
427 .arg(database)
428 .build()
429 }
430
431 #[must_use]
433 pub fn gdb(program: &str) -> SessionConfig {
434 SessionBuilder::new().command("gdb").arg(program).build()
435 }
436
437 #[must_use]
439 pub fn lldb(program: &str) -> SessionConfig {
440 SessionBuilder::new().command("lldb").arg(program).build()
441 }
442
443 #[must_use]
445 pub fn lua() -> SessionConfig {
446 SessionBuilder::new().command("lua").arg("-i").build()
447 }
448
449 #[must_use]
451 pub fn perl() -> SessionConfig {
452 SessionBuilder::new().command("perl").arg("-de0").build()
453 }
454
455 #[must_use]
457 pub fn r() -> SessionConfig {
458 SessionBuilder::new()
459 .command("R")
460 .arg("--no-save")
461 .arg("--no-restore")
462 .build()
463 }
464
465 #[must_use]
467 pub fn julia() -> SessionConfig {
468 SessionBuilder::new().command("julia").build()
469 }
470
471 #[must_use]
473 pub fn scala() -> SessionConfig {
474 SessionBuilder::new().command("scala").build()
475 }
476
477 #[must_use]
479 pub fn iex() -> SessionConfig {
480 SessionBuilder::new().command("iex").build()
481 }
482
483 #[must_use]
485 pub fn clojure() -> SessionConfig {
486 SessionBuilder::new().command("clj").build()
487 }
488
489 #[must_use]
491 pub fn ghci() -> SessionConfig {
492 SessionBuilder::new().command("ghci").build()
493 }
494
495 #[must_use]
497 pub fn ocaml() -> SessionConfig {
498 SessionBuilder::new().command("ocaml").build()
499 }
500
501 #[must_use]
503 pub fn kubectl_exec(pod: &str) -> SessionConfig {
504 SessionBuilder::new()
505 .command("kubectl")
506 .arg("exec")
507 .arg("-it")
508 .arg(pod)
509 .arg("--")
510 .arg("/bin/sh")
511 .build()
512 }
513
514 #[must_use]
516 pub fn kubectl_exec_ns(namespace: &str, pod: &str, shell: &str) -> SessionConfig {
517 SessionBuilder::new()
518 .command("kubectl")
519 .arg("exec")
520 .arg("-it")
521 .arg("-n")
522 .arg(namespace)
523 .arg(pod)
524 .arg("--")
525 .arg(shell)
526 .build()
527 }
528
529 #[must_use]
531 pub fn screen_attach(session_name: &str) -> SessionConfig {
532 SessionBuilder::new()
533 .command("screen")
534 .arg("-r")
535 .arg(session_name)
536 .build()
537 }
538
539 #[must_use]
541 pub fn tmux_attach(session_name: &str) -> SessionConfig {
542 SessionBuilder::new()
543 .command("tmux")
544 .arg("attach")
545 .arg("-t")
546 .arg(session_name)
547 .build()
548 }
549
550 #[must_use]
552 pub fn ssh_port(host: &str, port: u16) -> SessionConfig {
553 SessionBuilder::new()
554 .command("ssh")
555 .arg("-p")
556 .arg(port.to_string())
557 .arg(host)
558 .timeout(Duration::from_secs(30))
559 .build()
560 }
561
562 #[must_use]
564 pub fn ssh_full(user: &str, host: &str, port: u16) -> SessionConfig {
565 SessionBuilder::new()
566 .command("ssh")
567 .arg("-p")
568 .arg(port.to_string())
569 .arg(format!("{user}@{host}"))
570 .timeout(Duration::from_secs(30))
571 .build()
572 }
573
574 #[must_use]
576 pub fn ssh_key(user: &str, host: &str, key_file: &str) -> SessionConfig {
577 SessionBuilder::new()
578 .command("ssh")
579 .arg("-i")
580 .arg(key_file)
581 .arg(format!("{user}@{host}"))
582 .timeout(Duration::from_secs(30))
583 .build()
584 }
585
586 #[must_use]
588 pub fn vagrant_ssh() -> SessionConfig {
589 SessionBuilder::new()
590 .command("vagrant")
591 .arg("ssh")
592 .timeout(Duration::from_secs(30))
593 .build()
594 }
595
596 #[must_use]
598 pub fn vagrant_ssh_machine(machine: &str) -> SessionConfig {
599 SessionBuilder::new()
600 .command("vagrant")
601 .arg("ssh")
602 .arg(machine)
603 .timeout(Duration::from_secs(30))
604 .build()
605 }
606
607 #[must_use]
609 pub fn sftp(host: &str) -> SessionConfig {
610 SessionBuilder::new()
611 .command("sftp")
612 .arg(host)
613 .timeout(Duration::from_secs(30))
614 .build()
615 }
616
617 #[must_use]
619 pub fn sftp_user(user: &str, host: &str) -> SessionConfig {
620 SessionBuilder::new()
621 .command("sftp")
622 .arg(format!("{user}@{host}"))
623 .timeout(Duration::from_secs(30))
624 .build()
625 }
626
627 #[must_use]
629 pub fn ftp(host: &str) -> SessionConfig {
630 SessionBuilder::new()
631 .command("ftp")
632 .arg(host)
633 .timeout(Duration::from_secs(30))
634 .build()
635 }
636
637 #[must_use]
639 pub fn netcat(host: &str, port: u16) -> SessionConfig {
640 SessionBuilder::new()
641 .command("nc")
642 .arg(host)
643 .arg(port.to_string())
644 .build()
645 }
646
647 #[must_use]
649 pub fn socat(address: &str) -> SessionConfig {
650 SessionBuilder::new()
651 .command("socat")
652 .arg("-")
653 .arg(address)
654 .build()
655 }
656
657 #[must_use]
659 pub fn minicom(device: &str) -> SessionConfig {
660 SessionBuilder::new()
661 .command("minicom")
662 .arg("-D")
663 .arg(device)
664 .build()
665 }
666
667 #[must_use]
669 pub fn screen_serial(device: &str, baud_rate: u32) -> SessionConfig {
670 SessionBuilder::new()
671 .command("screen")
672 .arg(device)
673 .arg(baud_rate.to_string())
674 .build()
675 }
676
677 #[must_use]
679 pub fn picocom(device: &str, baud_rate: u32) -> SessionConfig {
680 SessionBuilder::new()
681 .command("picocom")
682 .arg("-b")
683 .arg(baud_rate.to_string())
684 .arg(device)
685 .build()
686 }
687
688 #[must_use]
690 pub fn aws_ssm(instance_id: &str) -> SessionConfig {
691 SessionBuilder::new()
692 .command("aws")
693 .arg("ssm")
694 .arg("start-session")
695 .arg("--target")
696 .arg(instance_id)
697 .timeout(Duration::from_secs(60))
698 .build()
699 }
700
701 #[must_use]
703 pub fn az_serial_console(resource_group: &str, vm_name: &str) -> SessionConfig {
704 SessionBuilder::new()
705 .command("az")
706 .arg("serial-console")
707 .arg("connect")
708 .arg("--resource-group")
709 .arg(resource_group)
710 .arg("--name")
711 .arg(vm_name)
712 .timeout(Duration::from_secs(60))
713 .build()
714 }
715
716 #[must_use]
718 pub fn gcloud_ssh(instance: &str, zone: &str) -> SessionConfig {
719 SessionBuilder::new()
720 .command("gcloud")
721 .arg("compute")
722 .arg("ssh")
723 .arg(instance)
724 .arg("--zone")
725 .arg(zone)
726 .timeout(Duration::from_secs(60))
727 .build()
728 }
729
730 #[must_use]
732 pub fn evcxr() -> SessionConfig {
733 SessionBuilder::new().command("evcxr").build()
734 }
735
736 #[must_use]
738 pub fn gore() -> SessionConfig {
739 SessionBuilder::new().command("gore").build()
740 }
741
742 #[must_use]
744 pub fn php() -> SessionConfig {
745 SessionBuilder::new().command("php").arg("-a").build()
746 }
747
748 #[must_use]
750 pub fn swift() -> SessionConfig {
751 SessionBuilder::new().command("swift").build()
752 }
753
754 #[must_use]
756 pub fn kotlin() -> SessionConfig {
757 SessionBuilder::new().command("kotlin").build()
758 }
759
760 #[must_use]
762 pub fn groovysh() -> SessionConfig {
763 SessionBuilder::new().command("groovysh").build()
764 }
765
766 #[must_use]
768 pub fn ts_node() -> SessionConfig {
769 SessionBuilder::new().command("ts-node").build()
770 }
771
772 #[must_use]
774 pub fn deno() -> SessionConfig {
775 SessionBuilder::new().command("deno").build()
776 }
777
778 #[must_use]
780 pub fn bun() -> SessionConfig {
781 SessionBuilder::new().command("bun").arg("repl").build()
782 }
783
784 #[must_use]
786 pub fn default_shell() -> String {
787 std::env::var("SHELL").unwrap_or_else(|_| {
788 if cfg!(windows) {
789 "cmd.exe".to_string()
790 } else {
791 "/bin/sh".to_string()
792 }
793 })
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800
801 #[test]
802 fn builder_basic() {
803 let config = SessionBuilder::new()
804 .command("/bin/bash")
805 .arg("-c")
806 .arg("echo hello")
807 .build();
808
809 assert_eq!(config.command, "/bin/bash");
810 assert_eq!(config.args, vec!["-c", "echo hello"]);
811 }
812
813 #[test]
814 fn builder_env() {
815 let config = SessionBuilder::new()
816 .command("test")
817 .env("FOO", "bar")
818 .env("BAZ", "qux")
819 .build();
820
821 assert_eq!(config.env.get("FOO"), Some(&"bar".to_string()));
822 assert_eq!(config.env.get("BAZ"), Some(&"qux".to_string()));
823 }
824
825 #[test]
826 fn builder_timeout() {
827 let config = SessionBuilder::new()
828 .command("test")
829 .timeout(Duration::from_secs(60))
830 .build();
831
832 assert_eq!(config.timeout.default, Duration::from_secs(60));
833 }
834
835 #[test]
836 fn quick_session_bash() {
837 let config = QuickSession::bash();
838 assert_eq!(config.command, "/bin/bash");
839 assert!(config.args.contains(&"--norc".to_string()));
840 }
841
842 #[test]
843 fn quick_session_ssh() {
844 let config = QuickSession::ssh_user("admin", "example.com");
845 assert_eq!(config.command, "ssh");
846 assert!(config.args.contains(&"admin@example.com".to_string()));
847 }
848
849 #[test]
850 fn quick_session_cmd() {
851 let config = QuickSession::cmd();
852 assert_eq!(config.command, "cmd.exe");
853 assert_eq!(config.line_ending, LineEnding::Cr);
854 }
855
856 #[test]
857 fn quick_session_powershell() {
858 let config = QuickSession::powershell();
859 #[cfg(windows)]
860 assert_eq!(config.command, "powershell.exe");
861 #[cfg(not(windows))]
862 assert_eq!(config.command, "pwsh");
863 assert!(config.args.contains(&"-NoLogo".to_string()));
864 assert!(config.args.contains(&"-NoProfile".to_string()));
865 }
866
867 #[test]
868 fn quick_session_zsh() {
869 let config = QuickSession::zsh();
870 assert_eq!(config.command, "/bin/zsh");
871 assert!(config.args.contains(&"--no-rcs".to_string()));
872 }
873
874 #[test]
875 fn quick_session_fish() {
876 let config = QuickSession::fish();
877 assert_eq!(config.command, "fish");
878 assert!(config.args.contains(&"--no-config".to_string()));
879 }
880
881 #[test]
882 fn quick_session_python() {
883 let config = QuickSession::python();
884 #[cfg(windows)]
885 assert_eq!(config.command, "python");
886 #[cfg(not(windows))]
887 assert_eq!(config.command, "python3");
888 assert!(config.args.contains(&"-i".to_string()));
889 }
890
891 #[test]
892 fn quick_session_node() {
893 let config = QuickSession::node();
894 assert_eq!(config.command, "node");
895 }
896
897 #[test]
898 fn quick_session_ruby() {
899 let config = QuickSession::ruby();
900 assert_eq!(config.command, "irb");
901 assert!(config.args.contains(&"--simple-prompt".to_string()));
902 }
903
904 #[test]
905 fn quick_session_mysql() {
906 let config = QuickSession::mysql("localhost", "root", "testdb");
907 assert_eq!(config.command, "mysql");
908 assert!(config.args.contains(&"-h".to_string()));
909 assert!(config.args.contains(&"localhost".to_string()));
910 assert!(config.args.contains(&"-u".to_string()));
911 assert!(config.args.contains(&"root".to_string()));
912 assert!(config.args.contains(&"testdb".to_string()));
913 }
914
915 #[test]
916 fn quick_session_psql() {
917 let config = QuickSession::psql("localhost", "postgres", "mydb");
918 assert_eq!(config.command, "psql");
919 assert!(config.args.contains(&"-h".to_string()));
920 assert!(config.args.contains(&"-U".to_string()));
921 assert!(config.args.contains(&"postgres".to_string()));
922 }
923
924 #[test]
925 fn quick_session_docker_exec() {
926 let config = QuickSession::docker_exec("my-container");
927 assert_eq!(config.command, "docker");
928 assert!(config.args.contains(&"exec".to_string()));
929 assert!(config.args.contains(&"-it".to_string()));
930 assert!(config.args.contains(&"my-container".to_string()));
931 assert!(config.args.contains(&"/bin/sh".to_string()));
932 }
933
934 #[test]
935 fn quick_session_docker_run() {
936 let config = QuickSession::docker_run("ubuntu:latest");
937 assert_eq!(config.command, "docker");
938 assert!(config.args.contains(&"run".to_string()));
939 assert!(config.args.contains(&"-it".to_string()));
940 assert!(config.args.contains(&"--rm".to_string()));
941 assert!(config.args.contains(&"ubuntu:latest".to_string()));
942 }
943
944 #[test]
945 fn quick_session_redis() {
946 let config = QuickSession::redis_cli("redis.example.com");
947 assert_eq!(config.command, "redis-cli");
948 assert!(config.args.contains(&"-h".to_string()));
949 assert!(config.args.contains(&"redis.example.com".to_string()));
950 }
951
952 #[test]
953 fn quick_session_sqlite() {
954 let config = QuickSession::sqlite("test.db");
955 assert_eq!(config.command, "sqlite3");
956 assert!(config.args.contains(&"test.db".to_string()));
957 }
958
959 #[test]
960 fn quick_session_gdb() {
961 let config = QuickSession::gdb("./my_program");
962 assert_eq!(config.command, "gdb");
963 assert!(config.args.contains(&"./my_program".to_string()));
964 }
965
966 #[test]
967 fn quick_session_kubectl() {
968 let config = QuickSession::kubectl_exec("my-pod");
969 assert_eq!(config.command, "kubectl");
970 assert!(config.args.contains(&"exec".to_string()));
971 assert!(config.args.contains(&"-it".to_string()));
972 assert!(config.args.contains(&"my-pod".to_string()));
973 assert!(config.args.contains(&"--".to_string()));
974 assert!(config.args.contains(&"/bin/sh".to_string()));
975 }
976
977 #[test]
978 fn quick_session_kubectl_ns() {
979 let config = QuickSession::kubectl_exec_ns("production", "api-pod", "/bin/bash");
980 assert_eq!(config.command, "kubectl");
981 assert!(config.args.contains(&"-n".to_string()));
982 assert!(config.args.contains(&"production".to_string()));
983 assert!(config.args.contains(&"api-pod".to_string()));
984 assert!(config.args.contains(&"/bin/bash".to_string()));
985 }
986
987 #[test]
988 fn quick_session_repls() {
989 assert_eq!(QuickSession::lua().command, "lua");
991 assert_eq!(QuickSession::julia().command, "julia");
992 assert_eq!(QuickSession::scala().command, "scala");
993 assert_eq!(QuickSession::iex().command, "iex");
994 assert_eq!(QuickSession::clojure().command, "clj");
995 assert_eq!(QuickSession::ghci().command, "ghci");
996 assert_eq!(QuickSession::ocaml().command, "ocaml");
997 assert_eq!(QuickSession::r().command, "R");
998 }
999
1000 #[test]
1001 fn quick_session_tmux_screen() {
1002 let config = QuickSession::tmux_attach("mysession");
1003 assert_eq!(config.command, "tmux");
1004 assert!(config.args.contains(&"attach".to_string()));
1005 assert!(config.args.contains(&"-t".to_string()));
1006 assert!(config.args.contains(&"mysession".to_string()));
1007
1008 let config = QuickSession::screen_attach("myscreen");
1009 assert_eq!(config.command, "screen");
1010 assert!(config.args.contains(&"-r".to_string()));
1011 assert!(config.args.contains(&"myscreen".to_string()));
1012 }
1013
1014 #[test]
1015 fn quick_session_ssh_variants() {
1016 let config = QuickSession::ssh_port("example.com", 2222);
1018 assert_eq!(config.command, "ssh");
1019 assert!(config.args.contains(&"-p".to_string()));
1020 assert!(config.args.contains(&"2222".to_string()));
1021 assert!(config.args.contains(&"example.com".to_string()));
1022
1023 let config = QuickSession::ssh_full("admin", "server.com", 2222);
1025 assert_eq!(config.command, "ssh");
1026 assert!(config.args.contains(&"-p".to_string()));
1027 assert!(config.args.contains(&"2222".to_string()));
1028 assert!(config.args.contains(&"admin@server.com".to_string()));
1029
1030 let config = QuickSession::ssh_key("root", "host.com", "/path/to/key");
1032 assert_eq!(config.command, "ssh");
1033 assert!(config.args.contains(&"-i".to_string()));
1034 assert!(config.args.contains(&"/path/to/key".to_string()));
1035 assert!(config.args.contains(&"root@host.com".to_string()));
1036 }
1037
1038 #[test]
1039 fn quick_session_vagrant() {
1040 let config = QuickSession::vagrant_ssh();
1041 assert_eq!(config.command, "vagrant");
1042 assert!(config.args.contains(&"ssh".to_string()));
1043
1044 let config = QuickSession::vagrant_ssh_machine("web");
1045 assert_eq!(config.command, "vagrant");
1046 assert!(config.args.contains(&"ssh".to_string()));
1047 assert!(config.args.contains(&"web".to_string()));
1048 }
1049
1050 #[test]
1051 fn quick_session_file_transfer() {
1052 let config = QuickSession::sftp("server.com");
1053 assert_eq!(config.command, "sftp");
1054 assert!(config.args.contains(&"server.com".to_string()));
1055
1056 let config = QuickSession::sftp_user("admin", "server.com");
1057 assert_eq!(config.command, "sftp");
1058 assert!(config.args.contains(&"admin@server.com".to_string()));
1059
1060 let config = QuickSession::ftp("ftp.example.com");
1061 assert_eq!(config.command, "ftp");
1062 assert!(config.args.contains(&"ftp.example.com".to_string()));
1063 }
1064
1065 #[test]
1066 fn quick_session_network_tools() {
1067 let config = QuickSession::netcat("localhost", 8080);
1068 assert_eq!(config.command, "nc");
1069 assert!(config.args.contains(&"localhost".to_string()));
1070 assert!(config.args.contains(&"8080".to_string()));
1071
1072 let config = QuickSession::socat("TCP:server:1234");
1073 assert_eq!(config.command, "socat");
1074 assert!(config.args.contains(&"-".to_string()));
1075 assert!(config.args.contains(&"TCP:server:1234".to_string()));
1076 }
1077
1078 #[test]
1079 fn quick_session_serial_terminals() {
1080 let config = QuickSession::minicom("/dev/ttyUSB0");
1081 assert_eq!(config.command, "minicom");
1082 assert!(config.args.contains(&"-D".to_string()));
1083 assert!(config.args.contains(&"/dev/ttyUSB0".to_string()));
1084
1085 let config = QuickSession::screen_serial("/dev/ttyACM0", 115_200);
1086 assert_eq!(config.command, "screen");
1087 assert!(config.args.contains(&"/dev/ttyACM0".to_string()));
1088 assert!(config.args.contains(&"115200".to_string()));
1089
1090 let config = QuickSession::picocom("/dev/ttyS0", 9600);
1091 assert_eq!(config.command, "picocom");
1092 assert!(config.args.contains(&"-b".to_string()));
1093 assert!(config.args.contains(&"9600".to_string()));
1094 assert!(config.args.contains(&"/dev/ttyS0".to_string()));
1095 }
1096
1097 #[test]
1098 fn quick_session_cloud_providers() {
1099 let config = QuickSession::aws_ssm("i-1234567890abcdef0");
1100 assert_eq!(config.command, "aws");
1101 assert!(config.args.contains(&"ssm".to_string()));
1102 assert!(config.args.contains(&"start-session".to_string()));
1103 assert!(config.args.contains(&"--target".to_string()));
1104 assert!(config.args.contains(&"i-1234567890abcdef0".to_string()));
1105
1106 let config = QuickSession::az_serial_console("my-rg", "my-vm");
1107 assert_eq!(config.command, "az");
1108 assert!(config.args.contains(&"serial-console".to_string()));
1109 assert!(config.args.contains(&"connect".to_string()));
1110 assert!(config.args.contains(&"--resource-group".to_string()));
1111 assert!(config.args.contains(&"my-rg".to_string()));
1112 assert!(config.args.contains(&"--name".to_string()));
1113 assert!(config.args.contains(&"my-vm".to_string()));
1114
1115 let config = QuickSession::gcloud_ssh("instance-1", "us-central1-a");
1116 assert_eq!(config.command, "gcloud");
1117 assert!(config.args.contains(&"compute".to_string()));
1118 assert!(config.args.contains(&"ssh".to_string()));
1119 assert!(config.args.contains(&"instance-1".to_string()));
1120 assert!(config.args.contains(&"--zone".to_string()));
1121 assert!(config.args.contains(&"us-central1-a".to_string()));
1122 }
1123
1124 #[test]
1125 fn quick_session_additional_repls() {
1126 assert_eq!(QuickSession::evcxr().command, "evcxr");
1128
1129 assert_eq!(QuickSession::gore().command, "gore");
1131
1132 let config = QuickSession::php();
1134 assert_eq!(config.command, "php");
1135 assert!(config.args.contains(&"-a".to_string()));
1136
1137 assert_eq!(QuickSession::swift().command, "swift");
1139
1140 assert_eq!(QuickSession::kotlin().command, "kotlin");
1142
1143 assert_eq!(QuickSession::groovysh().command, "groovysh");
1145
1146 assert_eq!(QuickSession::ts_node().command, "ts-node");
1148
1149 assert_eq!(QuickSession::deno().command, "deno");
1151
1152 let config = QuickSession::bun();
1154 assert_eq!(config.command, "bun");
1155 assert!(config.args.contains(&"repl".to_string()));
1156 }
1157}