Skip to content

Commit

Permalink
Fix test fails and make tests available for all feature combinations
Browse files Browse the repository at this point in the history
  • Loading branch information
yescallop committed Apr 11, 2024
1 parent e47071c commit 9854a59
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 17 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jobs:
uses: dtolnay/rust-toolchain@nightly
- name: Test with default features
run: cargo test
- name: Build with no features
run: cargo build --no-default-features
- name: Build with feature std
run: cargo build --no-default-features -F std
- name: Build with feature net
run: cargo build --no-default-features -F net
- name: Test with no features
run: cargo test --tests --no-default-features
- name: Test with feature std
run: cargo test --tests --no-default-features -F std
- name: Test with feature net
run: cargo test --tests --no-default-features -F net
8 changes: 4 additions & 4 deletions src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
encoder::{Fragment, Path, Query, Userinfo},
EStr,
},
internal::{AuthMeta, HostMeta, Meta},
internal::{AuthMeta, Meta},
parser, Uri,
};
use alloc::string::String;
Expand Down Expand Up @@ -118,15 +118,15 @@ impl BuilderInner {
#[cfg(feature = "net")]
Host::Ipv4(addr) => {
write!(self.buf, "{addr}").unwrap();
auth_meta.host_meta = HostMeta::Ipv4(addr);
auth_meta.host_meta = crate::internal::HostMeta::Ipv4(addr);
}
#[cfg(feature = "net")]
Host::Ipv6(addr) => {
write!(self.buf, "[{addr}]").unwrap();
auth_meta.host_meta = HostMeta::Ipv6(addr);
auth_meta.host_meta = crate::internal::HostMeta::Ipv6(addr);
}
Host::RegName(name) => {
auth_meta.host_meta = parser::reparse_reg_name(name.as_str().as_bytes());
auth_meta.host_meta = parser::parse_v4_or_reg_name(name.as_str().as_bytes());
self.buf.push_str(name.as_str());
}
_ => unreachable!(),
Expand Down
70 changes: 68 additions & 2 deletions src/normalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,15 @@ pub(crate) fn normalize(u: Uri<&str>) -> Uri<String> {
auth_meta.host_bounds.0 = buf.len() as _;
match auth_meta.host_meta {
// An IPv4 address is always canonical.
HostMeta::Ipv4(_) => buf.push_str(auth.host()),
HostMeta::Ipv4(..) => buf.push_str(auth.host()),
#[cfg(feature = "net")]
HostMeta::Ipv6(addr) => write!(buf, "[{addr}]").unwrap(),
#[cfg(not(feature = "net"))]
HostMeta::Ipv6(..) => {
buf.push('[');
write_v6(&mut buf, parser::parse_v6(&auth.host().as_bytes()[1..]));
buf.push(']');
}
HostMeta::IpvFuture => {
let start = buf.len();
buf.push_str(auth.host());
Expand All @@ -56,7 +63,7 @@ pub(crate) fn normalize(u: Uri<&str>) -> Uri<String> {

if buf.len() < start + host.len() {
// Only reparse when the length is less than before.
auth_meta.host_meta = parser::reparse_reg_name(&buf.as_bytes()[start..]);
auth_meta.host_meta = parser::parse_v4_or_reg_name(&buf.as_bytes()[start..]);
}
}
}
Expand Down Expand Up @@ -123,3 +130,62 @@ fn normalize_estr(buf: &mut String, s: &str, to_lowercase: bool) {
}
}
}

// Taken from `std`.
#[cfg(not(feature = "net"))]
fn write_v6(buf: &mut String, segments: [u16; 8]) {
if let [0, 0, 0, 0, 0, 0xffff, ab, cd] = segments {
let [a, b] = ab.to_be_bytes();
let [c, d] = cd.to_be_bytes();
write!(buf, "::ffff:{}.{}.{}.{}", a, b, c, d).unwrap()
} else {
#[derive(Copy, Clone, Default)]
struct Span {
start: usize,
len: usize,
}

// Find the inner 0 span
let zeroes = {
let mut longest = Span::default();
let mut current = Span::default();

for (i, &segment) in segments.iter().enumerate() {
if segment == 0 {
if current.len == 0 {
current.start = i;
}

current.len += 1;

if current.len > longest.len {
longest = current;
}
} else {
current = Span::default();
}
}

longest
};

/// Write a colon-separated part of the address
#[inline]
fn write_subslice(buf: &mut String, chunk: &[u16]) {
if let Some((first, tail)) = chunk.split_first() {
write!(buf, "{:x}", first).unwrap();
for segment in tail {
write!(buf, ":{:x}", segment).unwrap();
}
}
}

if zeroes.len > 1 {
write_subslice(buf, &segments[..zeroes.start]);
buf.push_str("::");
write_subslice(buf, &segments[zeroes.start + zeroes.len..]);
} else {
write_subslice(buf, &segments);
}
}
}
7 changes: 6 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ impl<'a> Reader<'a> {
}
}

pub(crate) fn reparse_reg_name(bytes: &[u8]) -> HostMeta {
pub(crate) fn parse_v4_or_reg_name(bytes: &[u8]) -> HostMeta {
let mut reader = Reader::new(bytes);
match reader.read_v4() {
Some(_addr) if !reader.has_remaining() => HostMeta::Ipv4(
Expand All @@ -409,6 +409,11 @@ pub(crate) fn reparse_reg_name(bytes: &[u8]) -> HostMeta {
}
}

#[cfg(not(feature = "net"))]
pub(crate) fn parse_v6(bytes: &[u8]) -> [u16; 8] {
Reader::new(bytes).read_v6().unwrap()
}

impl<'a> Parser<'a> {
fn parse_from_scheme(&mut self) -> Result<()> {
self.read(SCHEME)?;
Expand Down
20 changes: 18 additions & 2 deletions tests/normalize.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(feature = "net")]
use core::net::{Ipv4Addr, Ipv6Addr};

use fluent_uri::{component::Host, Uri};
#[cfg(feature = "net")]
use fluent_uri::component::Host;

use fluent_uri::Uri;

#[test]
fn normalize() {
Expand Down Expand Up @@ -72,6 +76,7 @@ fn normalize() {
// Normal IPv4 address.
let u = Uri::parse("//127.0.0.1").unwrap();
assert_eq!(u.normalize(), "//127.0.0.1");
#[cfg(feature = "net")]
assert_eq!(
u.normalize().authority().unwrap().host_parsed(),
Host::Ipv4(Ipv4Addr::LOCALHOST)
Expand All @@ -80,6 +85,7 @@ fn normalize() {
// Percent-encoded IPv4 address.
let u = Uri::parse("//127.0.0.%31").unwrap();
assert_eq!(u.normalize(), "//127.0.0.1");
#[cfg(feature = "net")]
assert_eq!(
u.normalize().authority().unwrap().host_parsed(),
Host::Ipv4(Ipv4Addr::LOCALHOST)
Expand All @@ -88,6 +94,7 @@ fn normalize() {
// Normal IPv6 address.
let u = Uri::parse("//[::1]").unwrap();
assert_eq!(u.normalize(), "//[::1]");
#[cfg(feature = "net")]
assert_eq!(
u.normalize().authority().unwrap().host_parsed(),
Host::Ipv6(Ipv6Addr::LOCALHOST)
Expand All @@ -96,11 +103,20 @@ fn normalize() {
// Verbose IPv6 address.
let u = Uri::parse("//[0000:0000:0000::1]").unwrap();
assert_eq!(u.normalize(), "//[::1]");
#[cfg(feature = "net")]
assert_eq!(
u.normalize().authority().unwrap().host_parsed(),
Host::Ipv6(Ipv6Addr::LOCALHOST)
);

// IPv4-mapped IPv6 address.
let u = Uri::parse("//[0:0:0:0:0:ffff:192.0.2.1]").unwrap();
assert_eq!(u.normalize(), "//[::ffff:192.0.2.1]");

// Deprecated IPv4-compatible IPv6 address.
let u = Uri::parse("//[::192.0.2.1]").unwrap();
assert_eq!(u.normalize(), "//[::c000:201]");

// IPvFuture address.
let u = Uri::parse("//[v1FdE.AddR]").unwrap();
assert_eq!(u.normalize(), "//[v1fde.addr]");
Expand Down
9 changes: 8 additions & 1 deletion tests/parse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(feature = "net")]
use core::net::{Ipv4Addr, Ipv6Addr};

use fluent_uri::{component::Host, encoding::EStr, Uri};

Expand Down Expand Up @@ -47,6 +48,7 @@ fn parse_absolute() {
assert_eq!(a.as_str(), "[2001:db8::7]");
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "[2001:db8::7]");
#[cfg(feature = "net")]
assert_eq!(
a.host_parsed(),
Host::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x7))
Expand Down Expand Up @@ -83,6 +85,7 @@ fn parse_absolute() {
assert_eq!(a.as_str(), "192.0.2.16:80");
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "192.0.2.16");
#[cfg(feature = "net")]
assert_eq!(a.host_parsed(), Host::Ipv4(Ipv4Addr::new(192, 0, 2, 16)));
assert_eq!(a.port(), Some("80"));
assert_eq!(u.path(), "/");
Expand Down Expand Up @@ -117,6 +120,7 @@ fn parse_absolute() {
Some(EStr::new("cnn.example.com&story=breaking_news"))
);
assert_eq!(a.host(), "10.0.0.1");
#[cfg(feature = "net")]
assert_eq!(a.host_parsed(), Host::Ipv4(Ipv4Addr::new(10, 0, 0, 1)));
assert_eq!(a.port(), None);
assert_eq!(u.path(), "/top_story.htm");
Expand All @@ -141,6 +145,7 @@ fn parse_absolute() {
assert_eq!(a.as_str(), "127.0.0.1:");
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert_eq!(a.host_parsed(), Host::Ipv4(Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some(""));
assert_eq!(u.path(), "/");
Expand All @@ -153,6 +158,7 @@ fn parse_absolute() {
assert_eq!(a.as_str(), "127.0.0.1:8080");
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert_eq!(a.host_parsed(), Host::Ipv4(Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some("8080"));
assert_eq!(u.path(), "/");
Expand All @@ -165,6 +171,7 @@ fn parse_absolute() {
assert_eq!(a.as_str(), "127.0.0.1:80808");
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert_eq!(a.host_parsed(), Host::Ipv4(Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some("80808"));
assert_eq!(u.path(), "/");
Expand Down
4 changes: 3 additions & 1 deletion tests/parse_ip.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::net::{Ipv4Addr, Ipv6Addr};
#![cfg(feature = "net")]

use core::net::{Ipv4Addr, Ipv6Addr};

use fluent_uri::{component::Host, Uri};

Expand Down
2 changes: 2 additions & 0 deletions tests/to_socket_addrs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(all(feature = "net", feature = "std"))]

use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};

use fluent_uri::Uri;
Expand Down

0 comments on commit 9854a59

Please sign in to comment.