Skip to content

Commit 0d13439

Browse files
committed
test: [#1446] add more tests to metrics package
1 parent 4da4f83 commit 0d13439

File tree

10 files changed

+645
-2
lines changed

10 files changed

+645
-2
lines changed

packages/metrics/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
./.coverage
1+
.coverage

packages/metrics/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,28 @@ A library with the metrics types used by the [Torrust Tracker](https://github.co
66

77
[Crate documentation](https://docs.rs/torrust-tracker-metrics).
88

9+
## Testing
10+
11+
Run coverage report:
12+
13+
```console
14+
cargo llvm-cov --package torrust-tracker-metrics
15+
```
16+
17+
Generate LCOV report with `llvm-cov` (for Visual Studio Code extension):
18+
19+
```console
20+
mkdir -p ./.coverage
21+
cargo llvm-cov --package torrust-tracker-metrics --lcov --output-path=./.coverage/lcov.info
22+
```
23+
24+
Generate HTML report with `llvm-cov`:
25+
26+
```console
27+
mkdir -p ./.coverage
28+
cargo llvm-cov --package torrust-tracker-metrics --html --output-dir ./.coverage
29+
```
30+
931
## Acknowledgements
1032

1133
We copied some parts like units or function names and signatures from the crate [metrics](https://crates.io/crates/metrics) because we wanted to make it compatible as much as possible with it. In the future, we may consider using the `metrics` crate directly instead of maintaining our own version.

packages/metrics/cSpell.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"words": [
3+
"cloneable",
4+
"formatjson",
5+
"Gibibytes",
6+
"Kibibytes",
7+
"Mebibytes",
8+
"ñaca",
9+
"rstest",
10+
"subsec",
11+
"Tebibytes",
12+
"thiserror"
13+
],
14+
"enableFiletypes": [
15+
"dockerfile",
16+
"shellscript",
17+
"toml"
18+
]
19+
}

packages/metrics/src/aggregate.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,118 @@ impl From<AggregateValue> for f64 {
2626
value.0
2727
}
2828
}
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use approx::assert_relative_eq;
33+
34+
use super::*;
35+
36+
#[test]
37+
fn it_should_be_created_with_new() {
38+
let value = AggregateValue::new(42.5);
39+
assert_relative_eq!(value.value(), 42.5);
40+
}
41+
42+
#[test]
43+
fn it_should_return_the_inner_value() {
44+
let value = AggregateValue::new(123.456);
45+
assert_relative_eq!(value.value(), 123.456);
46+
}
47+
48+
#[test]
49+
fn it_should_handle_zero_value() {
50+
let value = AggregateValue::new(0.0);
51+
assert_relative_eq!(value.value(), 0.0);
52+
}
53+
54+
#[test]
55+
fn it_should_handle_negative_values() {
56+
let value = AggregateValue::new(-42.5);
57+
assert_relative_eq!(value.value(), -42.5);
58+
}
59+
60+
#[test]
61+
fn it_should_handle_infinity() {
62+
let value = AggregateValue::new(f64::INFINITY);
63+
assert_relative_eq!(value.value(), f64::INFINITY);
64+
}
65+
66+
#[test]
67+
fn it_should_handle_nan() {
68+
let value = AggregateValue::new(f64::NAN);
69+
assert!(value.value().is_nan());
70+
}
71+
72+
#[test]
73+
fn it_should_be_created_from_f64() {
74+
let value: AggregateValue = 42.5.into();
75+
assert_relative_eq!(value.value(), 42.5);
76+
}
77+
78+
#[test]
79+
fn it_should_convert_to_f64() {
80+
let value = AggregateValue::new(42.5);
81+
let f64_value: f64 = value.into();
82+
assert_relative_eq!(f64_value, 42.5);
83+
}
84+
85+
#[test]
86+
fn it_should_be_displayable() {
87+
let value = AggregateValue::new(42.5);
88+
assert_eq!(value.to_string(), "42.5");
89+
}
90+
91+
#[test]
92+
fn it_should_be_debuggable() {
93+
let value = AggregateValue::new(42.5);
94+
let debug_string = format!("{value:?}");
95+
assert_eq!(debug_string, "AggregateValue(42.5)");
96+
}
97+
98+
#[test]
99+
fn it_should_be_cloneable() {
100+
let value = AggregateValue::new(42.5);
101+
let cloned_value = value;
102+
assert_eq!(value, cloned_value);
103+
}
104+
105+
#[test]
106+
fn it_should_be_copyable() {
107+
let value = AggregateValue::new(42.5);
108+
let copied_value = value;
109+
assert_eq!(value, copied_value);
110+
}
111+
112+
#[test]
113+
fn it_should_support_equality_comparison() {
114+
let value1 = AggregateValue::new(42.5);
115+
let value2 = AggregateValue::new(42.5);
116+
let value3 = AggregateValue::new(43.0);
117+
118+
assert_eq!(value1, value2);
119+
assert_ne!(value1, value3);
120+
}
121+
122+
#[test]
123+
fn it_should_handle_special_float_values_in_equality() {
124+
let nan1 = AggregateValue::new(f64::NAN);
125+
let nan2 = AggregateValue::new(f64::NAN);
126+
let infinity = AggregateValue::new(f64::INFINITY);
127+
let neg_infinity = AggregateValue::new(f64::NEG_INFINITY);
128+
129+
// NaN is not equal to itself in IEEE 754
130+
assert_ne!(nan1, nan2);
131+
assert_eq!(infinity, AggregateValue::new(f64::INFINITY));
132+
assert_eq!(neg_infinity, AggregateValue::new(f64::NEG_INFINITY));
133+
assert_ne!(infinity, neg_infinity);
134+
}
135+
136+
#[test]
137+
fn it_should_handle_conversion_roundtrip() {
138+
let original_value = 42.5;
139+
let aggregate_value = AggregateValue::from(original_value);
140+
let converted_back: f64 = aggregate_value.into();
141+
assert_relative_eq!(original_value, converted_back);
142+
}
143+
}

packages/metrics/src/counter.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,160 @@ mod tests {
107107
let counter = Counter::new(42);
108108
assert_eq!(counter.to_prometheus(), "42");
109109
}
110+
111+
#[test]
112+
fn it_could_be_converted_from_u32() {
113+
let counter: Counter = 42u32.into();
114+
assert_eq!(counter.value(), 42);
115+
}
116+
117+
#[test]
118+
fn it_could_be_converted_from_i32() {
119+
let counter: Counter = 42i32.into();
120+
assert_eq!(counter.value(), 42);
121+
}
122+
123+
#[test]
124+
fn it_should_return_primitive_value() {
125+
let counter = Counter::new(123);
126+
assert_eq!(counter.primitive(), 123);
127+
}
128+
129+
#[test]
130+
fn it_should_handle_zero_value() {
131+
let counter = Counter::new(0);
132+
assert_eq!(counter.value(), 0);
133+
assert_eq!(counter.primitive(), 0);
134+
}
135+
136+
#[test]
137+
fn it_should_handle_large_values() {
138+
let counter = Counter::new(u64::MAX);
139+
assert_eq!(counter.value(), u64::MAX);
140+
}
141+
142+
#[test]
143+
fn it_should_handle_u32_max_conversion() {
144+
let counter: Counter = u32::MAX.into();
145+
assert_eq!(counter.value(), u64::from(u32::MAX));
146+
}
147+
148+
#[test]
149+
fn it_should_handle_i32_max_conversion() {
150+
let counter: Counter = i32::MAX.into();
151+
assert_eq!(counter.value(), i32::MAX as u64);
152+
}
153+
154+
#[test]
155+
fn it_should_handle_negative_i32_conversion() {
156+
let counter: Counter = (-42i32).into();
157+
#[allow(clippy::cast_sign_loss)]
158+
let expected = (-42i32) as u64;
159+
assert_eq!(counter.value(), expected);
160+
}
161+
162+
#[test]
163+
fn it_should_handle_i32_min_conversion() {
164+
let counter: Counter = i32::MIN.into();
165+
#[allow(clippy::cast_sign_loss)]
166+
let expected = i32::MIN as u64;
167+
assert_eq!(counter.value(), expected);
168+
}
169+
170+
#[test]
171+
fn it_should_handle_large_increments() {
172+
let mut counter = Counter::new(100);
173+
counter.increment(1000);
174+
assert_eq!(counter.value(), 1100);
175+
176+
counter.increment(u64::MAX - 1100);
177+
assert_eq!(counter.value(), u64::MAX);
178+
}
179+
180+
#[test]
181+
fn it_should_support_multiple_absolute_operations() {
182+
let mut counter = Counter::new(0);
183+
184+
counter.absolute(100);
185+
assert_eq!(counter.value(), 100);
186+
187+
counter.absolute(50);
188+
assert_eq!(counter.value(), 50);
189+
190+
counter.absolute(0);
191+
assert_eq!(counter.value(), 0);
192+
}
193+
194+
#[test]
195+
fn it_should_be_displayable() {
196+
let counter = Counter::new(42);
197+
assert_eq!(counter.to_string(), "42");
198+
199+
let counter = Counter::new(0);
200+
assert_eq!(counter.to_string(), "0");
201+
}
202+
203+
#[test]
204+
fn it_should_be_debuggable() {
205+
let counter = Counter::new(42);
206+
let debug_string = format!("{counter:?}");
207+
assert_eq!(debug_string, "Counter(42)");
208+
}
209+
210+
#[test]
211+
fn it_should_be_cloneable() {
212+
let counter = Counter::new(42);
213+
let cloned_counter = counter.clone();
214+
assert_eq!(counter, cloned_counter);
215+
assert_eq!(counter.value(), cloned_counter.value());
216+
}
217+
218+
#[test]
219+
fn it_should_support_equality_comparison() {
220+
let counter1 = Counter::new(42);
221+
let counter2 = Counter::new(42);
222+
let counter3 = Counter::new(43);
223+
224+
assert_eq!(counter1, counter2);
225+
assert_ne!(counter1, counter3);
226+
}
227+
228+
#[test]
229+
fn it_should_have_default_value() {
230+
let counter = Counter::default();
231+
assert_eq!(counter.value(), 0);
232+
}
233+
234+
#[test]
235+
fn it_should_handle_conversion_roundtrip() {
236+
let original_value = 12345u64;
237+
let counter = Counter::from(original_value);
238+
let converted_back: u64 = counter.into();
239+
assert_eq!(original_value, converted_back);
240+
}
241+
242+
#[test]
243+
fn it_should_handle_u32_conversion_roundtrip() {
244+
let original_value = 12345u32;
245+
let counter = Counter::from(original_value);
246+
assert_eq!(counter.value(), u64::from(original_value));
247+
}
248+
249+
#[test]
250+
fn it_should_handle_i32_conversion_roundtrip() {
251+
let original_value = 12345i32;
252+
let counter = Counter::from(original_value);
253+
#[allow(clippy::cast_sign_loss)]
254+
let expected = original_value as u64;
255+
assert_eq!(counter.value(), expected);
256+
}
257+
258+
#[test]
259+
fn it_should_serialize_large_values_to_prometheus() {
260+
let counter = Counter::new(u64::MAX);
261+
assert_eq!(counter.to_prometheus(), u64::MAX.to_string());
262+
263+
let counter = Counter::new(0);
264+
assert_eq!(counter.to_prometheus(), "0");
265+
}
110266
}

0 commit comments

Comments
 (0)