• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

johnallen3d / mpc-rs / #172

27 Dec 2023 02:57PM UTC coverage: 20.149%. Remained the same
#172

push

johnallen3d
refactor: move to workspace project

- separate shared logic into a library
- `cli` is now a thin wrapper of `lib` and arg parsing

Resolves #79

4 of 23 new or added lines in 4 files covered. (17.39%)

227 existing lines in 2 files now uncovered.

135 of 670 relevant lines covered (20.15%)

1.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

10.14
/cli/src/main.rs
1
#![deny(clippy::pedantic)]
2
#![allow(clippy::missing_errors_doc)]
3
#![allow(clippy::missing_panics_doc)]
4
use std::io::BufRead;
5

6
use clap::Parser;
7

8
mod args;
9

10
use args::{Cli, Commands, OnOff};
11
use mpd_easy::Client;
12

UNCOV
13
fn main() {
×
14
    let args = Cli::parse();
×
15

16
    // safe to unwrap because we have default values
NEW
17
    let mut mpd = match Client::new(
×
18
        &args.bind_to_address.unwrap(),
×
19
        &args.port.unwrap(),
×
NEW
20
        args.format.to(),
×
21
    ) {
22
        Ok(client) => client,
×
23
        Err(e) => handle_error(e),
×
24
    };
25

26
    let result = match args.command {
×
27
        Some(Commands::Add { path }) => {
×
28
            mpd.add(&input_or_stdin(path, std::io::stdin().lock()))
×
29
        }
30
        Some(Commands::Crop) => mpd.crop(),
×
31
        Some(Commands::Del { position }) => mpd.del(position),
×
32
        Some(Commands::Current) => mpd.current(),
×
33
        Some(Commands::Play { position }) => mpd.play(position),
×
34
        Some(Commands::Next) => mpd.next(),
×
UNCOV
35
        Some(Commands::Prev) => mpd.prev(),
×
36
        Some(Commands::Pause) => mpd.pause(),
×
37
        Some(Commands::PauseIfPlaying) => mpd.pause_if_playing(),
×
38
        Some(Commands::Toggle) => mpd.toggle(),
×
39
        Some(Commands::Cdprev) => mpd.cdprev(),
×
40
        Some(Commands::Stop) => mpd.stop(),
×
41
        Some(Commands::Seek { position }) => mpd.seek(&position),
×
42
        Some(Commands::Seekthrough { position }) => mpd.seekthrough(&position),
×
43

44
        Some(Commands::Clear) => mpd.clear(),
×
45
        Some(Commands::Outputs) => mpd.outputs(),
×
46
        Some(Commands::Enable { args }) => mpd.enable(args),
×
UNCOV
47
        Some(Commands::Disable { args }) => mpd.disable(args),
×
UNCOV
48
        Some(Commands::Toggleoutput { args }) => mpd.toggle_output(args),
×
49
        Some(Commands::Queued) => mpd.queued(),
×
50
        Some(Commands::Shuffle) => mpd.shuffle(),
×
51
        Some(Commands::Lsplaylists) => mpd.lsplaylists(),
×
52
        Some(Commands::Load { name, range }) => mpd.load(&name, range),
×
53
        Some(Commands::Insert { uri }) => {
×
54
            mpd.insert(&input_or_stdin(uri, std::io::stdin().lock()))
×
55
        }
56
        Some(Commands::Prio {
57
            priority,
×
58
            position_or_range,
×
59
        }) => mpd.prio(&priority, &position_or_range),
×
UNCOV
60
        Some(Commands::Playlist { name }) => mpd.playlist(name),
×
61
        Some(Commands::Listall { file }) => mpd.listall(file.as_deref()),
×
62
        Some(Commands::Ls { directory }) => mpd.ls(directory.as_deref()),
×
NEW
63
        Some(Commands::Repeat { state }) => mpd.repeat(OnOff::to(&state)),
×
NEW
64
        Some(Commands::Random { state }) => mpd.random(OnOff::to(&state)),
×
NEW
65
        Some(Commands::Single { state }) => mpd.single(OnOff::to(&state)),
×
NEW
66
        Some(Commands::Consume { state }) => mpd.consume(OnOff::to(&state)),
×
UNCOV
67
        Some(Commands::Crossfade { seconds }) => mpd.crossfade(seconds),
×
68

UNCOV
69
        Some(Commands::Save { name }) => mpd.save(&name),
×
70
        Some(Commands::Rm { name }) => mpd.rm(&name),
×
71
        Some(Commands::Volume { volume }) => mpd.set_volume(&volume),
×
72
        Some(Commands::Stats) => mpd.stats(),
×
73
        Some(Commands::Version) => mpd.version(),
×
74

UNCOV
75
        Some(Commands::Status) | None => mpd.current_status(),
×
76
    };
77

78
    match result {
×
79
        Ok(Some(output)) => println!("{output}"),
×
80
        Ok(None) => (),
×
UNCOV
81
        Err(e) => handle_error(e),
×
82
    }
83
}
84

85
fn handle_error(error: impl std::fmt::Display) -> ! {
×
UNCOV
86
    let err_text = error.to_string();
×
UNCOV
87
    if !err_text.is_empty() {
×
UNCOV
88
        println!("{err_text}");
×
89
    }
UNCOV
90
    std::process::exit(1);
×
91
}
92

UNCOV
93
fn input_or_stdin<R: BufRead>(path: Option<String>, reader: R) -> String {
×
94
    if let Some(p) = path {
3✔
95
        return p;
1✔
96
    }
97

98
    let mut buffer = String::new();
1✔
99
    let mut reader = reader;
1✔
100

101
    reader
1✔
102
        .read_line(&mut buffer)
1✔
103
        .expect("error reading from input");
104

105
    buffer.trim().to_string()
1✔
106
}
107

108
#[cfg(test)]
109
mod tests {
110
    use super::*;
111
    use std::io::Cursor;
112

113
    #[test]
114
    fn test_input_or_stdin_with_path() {
115
        let path = Some("some_path".to_string());
116
        let cursor = Cursor::new("not_used");
117

118
        let result = input_or_stdin(path, cursor);
119
        assert_eq!(result, "some_path");
120
    }
121

122
    #[test]
123
    fn test_input_or_stdin_with_stdin() {
124
        let cursor = Cursor::new("from_stdin\n");
125

126
        let result = input_or_stdin(None, cursor);
127
        assert_eq!(result, "from_stdin");
128
    }
129
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc