Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for pure methods #189

Merged
merged 27 commits into from
Mar 9, 2021
Merged
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fe55750
Add test for json_insert macro and generate_random_string function.
ramsayleung Feb 26, 2021
89e142b
add test for headers module.
ramsayleung Feb 26, 2021
cd1f9c5
add test_read_token_cache test, and move all tests in oauth2.rs to te…
ramsayleung Feb 27, 2021
2cd8564
Add tests for append_device_id function.
ramsayleung Feb 27, 2021
b59982e
add test for endpoint_url and auth_headers function.
ramsayleung Feb 27, 2021
8d202ff
Fix cargo fmt error.
ramsayleung Feb 27, 2021
3f4960e
Fix clippy error.
ramsayleung Feb 27, 2021
0afba9e
add #[cfg(test)] attribute to fix unused import warning.
ramsayleung Feb 27, 2021
7cd65ad
update test_generate_random_string.
ramsayleung Feb 27, 2021
faf6543
add macro to create HashSet.
ramsayleung Feb 27, 2021
f78abf5
Replace macro `hashset!` to spotify-scope specific macro `scope!`.
ramsayleung Feb 28, 2021
10244b9
Fix cargo fmt error.
ramsayleung Feb 28, 2021
502b14f
Fix failed doc test
ramsayleung Feb 28, 2021
1177832
Fix cargo fmt error
ramsayleung Feb 28, 2021
275e56a
use scope to replace existing scope definitions.
ramsayleung Feb 28, 2021
582c3a3
Add spaceline between import statement and test functions.
ramsayleung Feb 28, 2021
6f75f8a
remove `#[doc(hidden)]` attr
ramsayleung Feb 28, 2021
2d0f555
recover `#[doc(hidden)]` attribute.
ramsayleung Mar 2, 2021
bae7f07
fix cargo check error.
ramsayleung Mar 2, 2021
5809eb9
move macros into `macros.rs`
ramsayleung Mar 2, 2021
b3b603b
Update CHANGELOG
ramsayleung Mar 3, 2021
c8b595f
rename scope! to scopes!
ramsayleung Mar 9, 2021
ccaac0a
Merge branch 'master' into ramsay_add_unit_tests
ramsayleung Mar 9, 2021
49e288b
Add reference to scope macro
ramsayleung Mar 9, 2021
82ff0db
Remove useless tests
ramsayleung Mar 9, 2021
c8d7d11
fix cargo check error
ramsayleung Mar 9, 2021
fffd831
fix cargo check error
ramsayleung Mar 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -9,3 +9,4 @@ Cargo.lock
.DS_Store
.spotify_cache/
**/target/
/.test_read_token_cache.json
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@ If we missed any change or there's something you'd like to discuss about this ve
+ `ExplicitContent`
+ Fix broken model links refering to Spotify documentation
- ([#188](https://github.com/ramsayleung/rspotify/pull/188)) Replace html links with intra-documentation links
- ([#189](https://github.com/ramsayleung/rspotify/pull/189)) Add `scopes!` macro to generate scope for `Token` from string literal

**Breaking changes:**
- `SpotifyClientCredentials` has been renamed to `Credentials` ([#129](https://github.com/ramsayleung/rspotify/pull/129)), and its members `client_id` and `client_secret` to `id` and `secret`, respectively.
10 changes: 5 additions & 5 deletions examples/current_user_recently_played.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use rspotify::client::SpotifyBuilder;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};

use std::collections::HashSet;
use rspotify::scope;
marioortizmanero marked this conversation as resolved.
Show resolved Hide resolved

#[tokio::main]
async fn main() {
@@ -31,9 +30,10 @@ async fn main() {
// .redirect_uri("http://localhost:8888/callback")
// .build()
// .unwrap();
let mut scopes = HashSet::new();
scopes.insert("user-read-recently-played".to_owned());
let oauth = OAuthBuilder::from_env().scope(scopes).build().unwrap();
let oauth = OAuthBuilder::from_env()
.scope(scopes!("user-read-recently-played"))
.build()
.unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
32 changes: 21 additions & 11 deletions examples/oauth_tokens.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

use rspotify::client::SpotifyBuilder;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scope;

#[tokio::main]
async fn main() {
@@ -18,17 +19,26 @@ async fn main() {
let creds = CredentialsBuilder::from_env().build().unwrap();

// Using every possible scope
let scope = "user-read-email user-read-private user-top-read \
user-read-recently-played user-follow-read user-library-read \
user-read-currently-playing user-read-playback-state \
user-read-playback-position playlist-read-collaborative \
playlist-read-private user-follow-modify user-library-modify \
user-modify-playback-state playlist-modify-public \
playlist-modify-private ugc-image-upload";
let oauth = OAuthBuilder::from_env()
.scope(scope.split_whitespace().map(|x| x.to_owned()).collect())
.build()
.unwrap();
let scope = scopes!(
"user-read-email",
"user-read-private",
"user-top-read",
"user-read-recently-played",
"user-follow-read",
"user-library-read",
"user-read-currently-playing",
"user-read-playback-state",
"user-read-playback-position",
"playlist-read-collaborative",
"playlist-read-private",
"user-follow-modify",
"user-library-modify",
"user-modify-playback-state",
"playlist-modify-public",
"playlist-modify-private",
"ugc-image-upload"
);
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
8 changes: 5 additions & 3 deletions examples/ureq/device.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rspotify::client::SpotifyBuilder;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scope;

use std::collections::HashSet;

@@ -30,9 +31,10 @@ fn main() {
// .redirect_uri("http://localhost:8888/callback")
// .build()
// .unwrap();
let mut scope = HashSet::new();
scope.insert("user-read-playback-state".to_owned());
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();
let oauth = OAuthBuilder::from_env()
.scope(scopes!("user-read-playback-state"))
.build()
.unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
8 changes: 5 additions & 3 deletions examples/ureq/me.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rspotify::client::SpotifyBuilder;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scope;

use std::collections::HashSet;

@@ -30,9 +31,10 @@ fn main() {
// .redirect_uri("http://localhost:8888/callback")
// .build()
// .unwrap();
let mut scope = HashSet::new();
scope.insert("user-read-playback-state".to_owned());
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();
let oauth = OAuthBuilder::from_env()
.scope(scopes!("user-read-playback-state"))
.build()
.unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
8 changes: 5 additions & 3 deletions examples/ureq/search.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rspotify::client::SpotifyBuilder;
use rspotify::model::{Country, Market, SearchType};
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scope;

use std::collections::HashSet;

@@ -31,9 +32,10 @@ fn main() {
// .redirect_uri("http://localhost:8888/callback")
// .build()
// .unwrap();
let mut scope = HashSet::new();
scope.insert("user-read-playback-state".to_owned());
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();
let oauth = OAuthBuilder::from_env()
.scope(scopes!("user-read-playback-state"))
.build()
.unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
8 changes: 5 additions & 3 deletions examples/ureq/seek_track.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rspotify::client::SpotifyBuilder;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scope;

use std::collections::HashSet;

@@ -30,9 +31,10 @@ fn main() {
// .redirect_uri("http://localhost:8888/callback")
// .build()
// .unwrap();
let mut scope = HashSet::new();
scope.insert("user-read-playback-state".to_owned());
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();
let oauth = OAuthBuilder::from_env()
.scope(scopes!("user-read-playback-state"))
.build()
.unwrap();

let mut spotify = SpotifyBuilder::default()
.credentials(creds)
5 changes: 3 additions & 2 deletions examples/webapp/src/main.rs
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ use rocket_contrib::json::JsonValue;
use rocket_contrib::templates::Template;
use rspotify::client::{ClientError, SpotifyBuilder};
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder, TokenBuilder};
use rspotify::scope;

use std::fs;
use std::{
@@ -75,10 +76,10 @@ fn check_cache_path_exists(cookies: &Cookies) -> (bool, PathBuf) {
fn init_spotify() -> SpotifyBuilder {
// Please notice that protocol of redirect_uri, make sure it's http
// (or https). It will fail if you mix them up.
let scope = "user-read-currently-playing playlist-modify-private";
let scope = scopes!("user-read-currently-playing playlist-modify-private");
marioortizmanero marked this conversation as resolved.
Show resolved Hide resolved
let oauth = OAuthBuilder::default()
.redirect_uri("http://localhost:8000/callback")
.scope(scope.split_whitespace().map(|x| x.to_owned()).collect())
.scope(scope)
.build()
.unwrap();

8 changes: 3 additions & 5 deletions examples/with_refresh_token.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
use rspotify::client::{Spotify, SpotifyBuilder};
use rspotify::model::Id;
use rspotify::oauth2::{CredentialsBuilder, OAuthBuilder};
use rspotify::scopes;

// Sample request that will follow some artists, print the user's
// followed artists, and then unfollow the artists.
@@ -57,11 +58,8 @@ async fn main() {

// The default credentials from the `.env` file will be used by default.
let creds = CredentialsBuilder::from_env().build().unwrap();
let scope = "user-follow-read user-follow-modify";
let oauth = OAuthBuilder::from_env()
.scope(scope.split_whitespace().map(|x| x.to_owned()).collect())
.build()
.unwrap();
let scope = scopes!("user-follow-read user-follow-modify");
let oauth = OAuthBuilder::from_env().scope(scope).build().unwrap();
let mut spotify = SpotifyBuilder::default()
.credentials(creds.clone())
.oauth(oauth.clone())
23 changes: 22 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
@@ -2044,7 +2044,7 @@ fn join_ids<'a, T: 'a + IdType>(ids: impl IntoIterator<Item = &'a Id<T>>) -> Str
}

#[cfg(test)]
mod tests {
mod test {
use super::*;

#[test]
@@ -2054,4 +2054,25 @@ mod tests {
let code = spotify.parse_response_code(url).unwrap();
assert_eq!(code, "AQD0yXvFEOvw");
}

#[test]
fn test_append_device_id_without_question_mark() {
let path = "me/player/play";
let device_id = Some("fdafdsadfa".to_owned());
let spotify = SpotifyBuilder::default().build().unwrap();
let new_path = spotify.append_device_id(path, device_id);
assert_eq!(new_path, "me/player/play?device_id=fdafdsadfa");
}

#[test]
fn test_append_device_id_with_question_mark() {
let path = "me/player/shuffle?state=true";
let device_id = Some("fdafdsadfa".to_owned());
let spotify = SpotifyBuilder::default().build().unwrap();
let new_path = spotify.append_device_id(path, device_id);
assert_eq!(
new_path,
"me/player/shuffle?state=true&device_id=fdafdsadfa"
);
}
}
66 changes: 66 additions & 0 deletions src/http/mod.rs
Original file line number Diff line number Diff line change
@@ -232,3 +232,69 @@ impl Spotify {
self.delete(url, Some(&headers), payload).await
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::client::SpotifyBuilder;
use crate::oauth2::TokenBuilder;
use crate::scopes;
use chrono::prelude::*;
use chrono::Duration;

#[test]
marioortizmanero marked this conversation as resolved.
Show resolved Hide resolved
fn test_bearer_auth() {
let access_token = "access_token";
let tok = TokenBuilder::default()
.access_token(access_token)
.build()
.unwrap();
let (auth, value) = headers::bearer_auth(&tok);
assert_eq!(auth, "authorization");
assert_eq!(value, "Bearer access_token");
}

#[test]
fn test_basic_auth() {
let (auth, value) = headers::basic_auth("ramsay", "123456");
assert_eq!(auth, "authorization");
assert_eq!(value, "Basic cmFtc2F5OjEyMzQ1Ng==");
}

#[test]
fn test_endpoint_url() {
let spotify = SpotifyBuilder::default().build().unwrap();
assert_eq!(
spotify.endpoint_url("me/player/play"),
"https://api.spotify.com/v1/me/player/play"
);
assert_eq!(
spotify.endpoint_url("http://api.spotify.com/v1/me/player/play"),
"http://api.spotify.com/v1/me/player/play"
);
assert_eq!(
spotify.endpoint_url("https://api.spotify.com/v1/me/player/play"),
"https://api.spotify.com/v1/me/player/play"
);
}

#[test]
fn test_auth_headers() {
let tok = TokenBuilder::default()
.access_token("test-access_token")
.expires_in(Duration::seconds(1))
.expires_at(Utc::now())
.scope(scopes!("playlist-read-private"))
.refresh_token("...")
.build()
.unwrap();

let spotify = SpotifyBuilder::default().token(tok).build().unwrap();

let headers = spotify.auth_headers().unwrap();
assert_eq!(
headers.get("authorization"),
Some(&"Bearer test-access_token".to_owned())
);
}
}
51 changes: 37 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -165,26 +165,15 @@ pub mod model;
#[cfg(not(all(feature = "client-reqwest", feature = "client-ureq")))]
pub mod oauth2;

#[macro_use]
mod macros;

#[cfg(all(feature = "client-reqwest", feature = "client-ureq"))]
compile_error!(
"`client-reqwest` and `client-ureq` features cannot both be enabled at the same time, \
if you want to use `client-ureq` you need to set `default-features = false`"
);

#[doc(hidden)]
mod macros {
/// Reduce boilerplate when inserting new elements in a JSON object.
#[macro_export]
macro_rules! json_insert {
($json:expr, $p1:expr, $p2:expr) => {
$json
.as_object_mut()
.unwrap()
.insert($p1.to_string(), json!($p2))
};
}
}

/// Generate `length` random chars
pub(in crate) fn generate_random_string(length: usize) -> String {
let alphanum: &[u8] =
@@ -197,3 +186,37 @@ pub(in crate) fn generate_random_string(length: usize) -> String {
.map(|byte| alphanum[*byte as usize % range] as char)
.collect()
}

#[cfg(test)]
mod test {
use super::{generate_random_string, json_insert, scopes};
use serde_json::json;
use std::collections::HashSet;

#[test]
fn test_hashset() {
let scope = scopes!("hello", "world", "foo", "bar");
assert_eq!(scope.len(), 4);
assert!(scope.contains(&"hello".to_owned()));
assert!(scope.contains(&"world".to_owned()));
assert!(scope.contains(&"foo".to_owned()));
assert!(scope.contains(&"bar".to_owned()));
}

#[test]
fn test_generate_random_string() {
let mut containers = HashSet::new();
for _ in 1..101 {
containers.insert(generate_random_string(10));
}
assert_eq!(containers.len(), 100);
}

#[test]
fn test_json_insert() {
let mut params = json!({});
let name = "ramsay";
json_insert!(params, "name", name);
assert_eq!(params["name"], name);
}
}
Loading