Skip to content

Commit

Permalink
Merge pull request #6 from busticated/feature/json
Browse files Browse the repository at this point in the history
feature/json
  • Loading branch information
busticated authored Oct 19, 2023
2 parents 01bed6e + 0502a3e commit 2bcb4ae
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 59 deletions.
5 changes: 5 additions & 0 deletions crates/node-js-release-info/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ repository.workspace = true
[dependencies]
reqwest = { version = "0.11.*" }
semver = "1.*"
serde = { version = "1.*", features = ["derive"], optional = true }
tokio = { version = "1.*", default-features = false, features = ["macros", "net", "time"] }

[dev-dependencies]
mockito = "1.*"
serde_json = "1.*"

[features]
json = ["dep:serde"]
19 changes: 19 additions & 0 deletions crates/node-js-release-info/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,23 @@ async fn main() -> Result<(), NodeJSRelInfoError> {
}
```

## Features

Full `json` serialization + deserialization is avaialable via the `json` feature.

```shell
cargo add node-js-release-info --features json
```

```rust
use node_js_release_info::{NodeJSRelInfo, NodeJSRelInfoError};

#[tokio::main]
async fn main() {
let info = NodeJSRelInfo::new("20.6.1").macos().arm64().to_owned();
let json = serde_json::to_string(&info).unwrap();
let info_deserialized = serde_json::from_str(&json).unwrap();
assert_eq!(info, info_deserialized);
}
```

15 changes: 15 additions & 0 deletions crates/node-js-release-info/src/arch.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
use crate::error::NodeJSRelInfoError;
#[cfg(feature = "json")]
use serde::{Deserialize, Serialize};
use std::env::consts::ARCH;
use std::fmt::{Display, Formatter};
use std::str::FromStr;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub enum NodeJSArch {
#[cfg_attr(feature = "json", serde(rename = "x64"))]
X64,
#[cfg_attr(feature = "json", serde(rename = "x86"))]
X86,
#[cfg_attr(feature = "json", serde(rename = "arm64"))]
ARM64,
#[cfg_attr(feature = "json", serde(rename = "armv7l"))]
ARMV7L,
#[cfg_attr(feature = "json", serde(rename = "ppc64le"))]
PPC64LE,
}

Expand Down Expand Up @@ -143,4 +151,11 @@ mod tests {
fn it_fails_when_arch_is_unrecognized() {
NodeJSArch::from_str("NOPE!").unwrap();
}

#[test]
fn it_serializes_and_deserializes() {
let arch_json = serde_json::to_string(&NodeJSArch::X64).unwrap();
let arch: NodeJSArch = serde_json::from_str(&arch_json).unwrap();
assert_eq!(arch, NodeJSArch::X64);
}
}
14 changes: 14 additions & 0 deletions crates/node-js-release-info/src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
use crate::error::NodeJSRelInfoError;
#[cfg(feature = "json")]
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub enum NodeJSPkgExt {
#[cfg_attr(feature = "json", serde(rename = "tar.gz"))]
Targz,
#[cfg_attr(feature = "json", serde(rename = "tar.xz"))]
Tarxz,
#[cfg_attr(feature = "json", serde(rename = "zip"))]
Zip,
#[cfg_attr(feature = "json", serde(rename = "msi"))]
Msi,
}

Expand Down Expand Up @@ -109,4 +116,11 @@ mod tests {
fn it_fails_when_arch_is_unrecognized() {
NodeJSPkgExt::from_str("NOPE!").unwrap();
}

#[test]
fn it_serializes_and_deserializes() {
let ext_json = serde_json::to_string(&NodeJSPkgExt::Tarxz).unwrap();
let ext: NodeJSPkgExt = serde_json::from_str(&ext_json).unwrap();
assert_eq!(ext, NodeJSPkgExt::Tarxz);
}
}
88 changes: 34 additions & 54 deletions crates/node-js-release-info/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ mod url;

use std::string::ToString;
use semver::Version;
#[cfg(feature = "json")]
use serde::{Serialize, Deserialize};
pub use crate::os::NodeJSOS;
pub use crate::arch::NodeJSArch;
pub use crate::error::NodeJSRelInfoError;
pub use crate::ext::NodeJSPkgExt;
use crate::url::NodeJSURLFormatter;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub struct NodeJSRelInfo {
/// The operating system for the Node.js distributable you are targeting
pub os: NodeJSOS,
Expand All @@ -30,6 +33,7 @@ pub struct NodeJSRelInfo {
pub sha256: String,
/// The fully qualified url for the Node.js distributable (populated after fetching)
pub url: String,
#[cfg_attr(feature = "json", serde(skip))]
url_fmt: NodeJSURLFormatter,
}

Expand Down Expand Up @@ -244,29 +248,6 @@ impl NodeJSRelInfo {
self.clone()
}

/// Creates JSON String from instance
///
/// # Examples
///
/// ```rust
/// use node_js_release_info::{NodeJSRelInfo, NodeJSRelInfoError};
/// let info = NodeJSRelInfo::new("20.6.1");
/// assert_eq!(info.to_json_string(), "{\"version\":\"20.6.1\",\"os\":\"linux\",\"arch\":\"x64\",\"filename\":\"node-v20.6.1-linux-x64.tar.gz\",\"sha256\":\"\",\"url\":\"\"}");
/// ```
// TODO (busticated): should probably just use serde
pub fn to_json_string(&self) -> String {
let entries = vec![
format!("\"version\":\"{}\"", self.version),
format!("\"os\":\"{}\"", self.os),
format!("\"arch\":\"{}\"", self.arch),
format!("\"filename\":\"{}\"", self.filename()),
format!("\"sha256\":\"{}\"", self.sha256),
format!("\"url\":\"{}\"", self.url),
];

format!("{{{}}}", entries.join(","))
}

/// Fetches Node.js metadata from the [releases download server](https://nodejs.org/download/release/)
///
/// # Examples
Expand Down Expand Up @@ -341,6 +322,8 @@ mod tests {
use mockito::{Server, Mock};
use super::*;

fn is_thread_safe<T: Sized + Send + Sync + Unpin>() {}

#[test]
fn it_initializes(){
let info = NodeJSRelInfo::new("1.0.0");
Expand All @@ -351,6 +334,7 @@ mod tests {
assert_eq!(info.filename, "".to_string());
assert_eq!(info.sha256, "".to_string());
assert_eq!(info.url, "".to_string());
is_thread_safe::<NodeJSRelInfo>();
}

#[test]
Expand Down Expand Up @@ -463,37 +447,6 @@ mod tests {
assert_ne!(info1, info2);
}

#[test]
fn it_gets_json_string() {
let mut info = NodeJSRelInfo::new("1.0.0").macos().x64().zip().to_owned();
info.sha256 = "fake-sha256".into();
info.url = "https://example.com/fake-url".into();
let json = info.to_json_string();
let result: Vec<&str> = json.split(',').collect();

assert_eq!(result, vec![
"{\"version\":\"1.0.0\"",
"\"os\":\"darwin\"",
"\"arch\":\"x64\"",
"\"filename\":\"node-v1.0.0-darwin-x64.zip\"",
"\"sha256\":\"fake-sha256\"",
"\"url\":\"https://example.com/fake-url\"}"
]);

info.windows().arm64().msi();
let json = info.to_json_string();
let result: Vec<&str> = json.split(',').collect();

assert_eq!(result, vec![
"{\"version\":\"1.0.0\"",
"\"os\":\"win\"",
"\"arch\":\"arm64\"",
"\"filename\":\"node-v1.0.0-arm64.msi\"",
"\"sha256\":\"fake-sha256\"",
"\"url\":\"https://example.com/fake-url\"}"
]);
}

#[test]
fn it_formats_filename() {
let info = NodeJSRelInfo::new("1.0.0").macos().x64().zip().to_owned();
Expand All @@ -505,6 +458,33 @@ mod tests {
assert_eq!(info.filename(), "node-v1.0.0-x64.msi");
}

#[test]
fn it_serializes_and_deserializes() {
let version = "20.6.1".to_string();
let filename = "node-v20.6.1-darwin-arm64.tar.gz".to_string();
let sha256 = "d8ba8018d45b294429b1a7646ccbeaeb2af3cdf45b5c91dabbd93e2a2035cb46".to_string();
let url = "https://nodejs.org/download/release/v20.6.1/node-v20.6.1-darwin-arm64.tar.gz".to_string();
let info_orig = NodeJSRelInfo {
os: NodeJSOS::Darwin,
arch: NodeJSArch::ARM64,
ext: NodeJSPkgExt::Targz,
version: version.clone(),
filename: filename.clone(),
sha256: sha256.clone(),
url: url.clone(),
..Default::default()
};
let info_json = serde_json::to_string(&info_orig).unwrap();
let info: NodeJSRelInfo = serde_json::from_str(&info_json).unwrap();
assert_eq!(info.os, NodeJSOS::Darwin);
assert_eq!(info.arch, NodeJSArch::ARM64);
assert_eq!(info.ext, NodeJSPkgExt::Targz);
assert_eq!(info.version, "20.6.1".to_string());
assert_eq!(info.filename, "node-v20.6.1-darwin-arm64.tar.gz".to_string());
assert_eq!(info.sha256, "d8ba8018d45b294429b1a7646ccbeaeb2af3cdf45b5c91dabbd93e2a2035cb46".to_string());
assert_eq!(info.url, "https://nodejs.org/download/release/v20.6.1/node-v20.6.1-darwin-arm64.tar.gz".to_string());
}

#[tokio::test]
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: InvalidVersion(\"NOPE!\")")]
async fn it_fails_to_fetch_info_when_version_is_invalid() {
Expand Down
13 changes: 13 additions & 0 deletions crates/node-js-release-info/src/os.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use crate::error::NodeJSRelInfoError;
#[cfg(feature = "json")]
use serde::{Deserialize, Serialize};
use std::env::consts::OS;
use std::fmt::{Display, Formatter};
use std::str::FromStr;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub enum NodeJSOS {
#[cfg_attr(feature = "json", serde(rename = "linux"))]
Linux,
#[cfg_attr(feature = "json", serde(rename = "darwin"))]
Darwin,
#[cfg_attr(feature = "json", serde(rename = "win"))]
Windows,
}

Expand Down Expand Up @@ -117,4 +123,11 @@ mod tests {
fn it_fails_when_os_cannot_be_determined_from_str() {
NodeJSOS::from_str("NOPE!").unwrap();
}

#[test]
fn it_serializes_and_deserializes() {
let os_json = serde_json::to_string(&NodeJSOS::Darwin).unwrap();
let os: NodeJSOS = serde_json::from_str(&os_json).unwrap();
assert_eq!(os, NodeJSOS::Darwin);
}
}
4 changes: 2 additions & 2 deletions xtask/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ impl<'a> Cargo<'a> {
{
let mut profile_ptn: OsString = path.into();
profile_ptn.push("/cargo-test-%p-%m.profraw");
let args = self.build_args([OsString::from("test")], [""]);
let args = self.build_args([OsString::from("test")], ["--all-features"]);
let envs = HashMap::from([
("CARGO_INCREMENTAL".into(), "0".into()),
("RUSTFLAGS".into(), "-Cinstrument-coverage".into()),
Expand Down Expand Up @@ -286,7 +286,7 @@ mod tests {
),
]);

assert_eq!(args, ["test"]);
assert_eq!(args, ["test", "--all-features"]);
assert_eq!(envs, Some(expected_envs));
}

Expand Down
6 changes: 3 additions & 3 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,12 +402,12 @@ fn init_tasks() -> Tasks {
println!(":::: Testing Examples...");
println!();

cargo.test(["--doc"]).run()?;
cargo.test(["--doc", "--all-features"]).run()?;

println!(":::: Rendering Docs...");
println!();

let mut args = vec!["--workspace", "--no-deps"];
let mut args = vec!["--workspace", "--no-deps", "--all-features"];

if opts.has("open") {
args.push("--open");
Expand Down Expand Up @@ -473,7 +473,7 @@ fn init_tasks() -> Tasks {
println!(":::::::::::::::::::::::::");
println!();

cargo.test([""]).run()?;
cargo.test(["--all-features"]).run()?;

println!(":::: Done!");
println!();
Expand Down

0 comments on commit 2bcb4ae

Please sign in to comment.