Skip to content

Commit

Permalink
Error handling (#19)
Browse files Browse the repository at this point in the history
* Add error handling

* Refactor error names

* Order response matching by status code

* Update tests

* Bump version
  • Loading branch information
disrupted authored May 23, 2021
1 parent afe14e5 commit ae9dbff
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 10 deletions.
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "blackd-client"
version = "0.0.3"
version = "0.0.4"
authors = ["disrupted <hi@salomonpopp.me>"]
edition = "2018"
description = "Blazing fast Python code formatting using Black"
Expand All @@ -13,6 +13,7 @@ categories = ["command-line-utilities"]
[dependencies]
minreq = "2.3.1"
clap = "3.0.0-beta.2"
custom_error = "1.9.2"

[dev-dependencies]
httpmock = "0.5.8"
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ Luckily there's [blackd](https://black.readthedocs.io/en/stable/usage_and_config

If you're using Black (or writing Python code in general) I recommend you to check it out!

> this is very early stage and experimental. It's literally < 50 LOC I hacked together in one evening, and I'll probably improve it as I learn more about Rust.
## Install

1. Install Black
Expand Down
69 changes: 63 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
use clap::{crate_version, AppSettings, Clap};
use custom_error::custom_error;
use std::{io, io::prelude::*};

/// Tiny HTTP client for the Black (blackd) Python code formatter
#[derive(Clap)]
#[clap(version = crate_version!())]
#[clap(setting = AppSettings::ColoredHelp)]
struct Opts {
/// URL of blackd server
#[clap(long, default_value = "http://localhost:45484")]
url: String,
}

custom_error! {BlackdError
Minreq{source: minreq::Error} = "{source}",
Syntax{details: String} = "Syntax Error: {details}",
Formatting{details: String} = "Formatting Error: {details}",
Unknown{status_code: i32, body: String} = "Unknown Error: {status_code}",
}

fn main() {
let opts: Opts = Opts::parse();
let stdin = read_stdin();
let result = format(opts.url, stdin.unwrap());
match result {
Ok(v) => print!("{}", v),
Err(e) => print!("Error formatting with blackd-client: {}", e),
Err(e) => {
eprint!("Error formatting with blackd-client: {}", e);
std::process::exit(1);
}
}
}

Expand All @@ -30,17 +42,23 @@ fn read_stdin() -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
Ok(buffer)
}

fn format(url: String, stdin: String) -> Result<String, minreq::Error> {
fn format(url: String, stdin: String) -> Result<String, BlackdError> {
let resp = minreq::post(url)
.with_header("X-Fast-Or-Safe", "fast")
.with_header("Content-Type", "text/plain; charset=utf-8")
.with_body(stdin.as_str())
.send()?;

let body = resp.as_str()?.to_string();
match resp.status_code {
204 => Ok(stdin), // input is already well-formatted
200 => Ok(resp.as_str()?.to_string()), // input was reformatted by Black
_ => Err(minreq::Error::Other("Error")),
200 => Ok(body), // input was reformatted by Black
204 => Ok(stdin), // input is already well-formatted
400 => Err(BlackdError::Syntax { details: body }),
500 => Err(BlackdError::Formatting { details: body }),
_ => Err(BlackdError::Unknown {
status_code: resp.status_code,
body,
}),
}
}

Expand Down Expand Up @@ -87,7 +105,45 @@ mod tests {
}

#[test]
fn test_format_error() {
fn test_syntax_error() {
let server = MockServer::start();
let mock = server.mock(|when, then| {
when.method("POST");
then.status(400)
.body("Cannot parse: 1:6: print('bad syntax'))");
});

let result = format(server.url(""), "print('bad syntax'))".to_string());

mock.assert();
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Syntax Error: Cannot parse: 1:6: print('bad syntax'))"
);
}

#[test]
fn test_formatting_error() {
let server = MockServer::start();
let mock = server.mock(|when, then| {
when.method("POST");
then.status(500)
.body("('EOF in multi-line statement', (2, 0))");
});

let result = format(server.url(""), "print(('bad syntax')".to_string());

mock.assert();
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Formatting Error: ('EOF in multi-line statement', (2, 0))"
);
}

#[test]
fn test_unknown_error() {
let server = MockServer::start();
let mock = server.mock(|when, then| {
when.method("POST");
Expand All @@ -98,5 +154,6 @@ mod tests {

mock.assert();
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Unknown Error: 418");
}
}

0 comments on commit ae9dbff

Please sign in to comment.