Skip to content

Commit ed544d7

Browse files
Add units.libsonnet (#37)
1 parent 6a0311c commit ed544d7

File tree

5 files changed

+404
-0
lines changed

5 files changed

+404
-0
lines changed

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ in the future, but also provides a place for less general, yet useful utilities.
2323
* [jsonpath](jsonpath.md)
2424
* [number](number.md)
2525
* [string](string.md)
26+
* [units](units.md)
2627
* [url](url.md)

docs/units.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
permalink: /units/
3+
---
4+
5+
# units
6+
7+
```jsonnet
8+
local units = import "github.com/jsonnet-libs/xtd/units.libsonnet"
9+
```
10+
11+
`units` implements helper functions for converting units.
12+
13+
## Index
14+
15+
* [`fn formatDuration(seconds)`](#fn-formatduration)
16+
* [`fn parseDuration(duration)`](#fn-parseduration)
17+
* [`fn parseKubernetesCPU(input)`](#fn-parsekubernetescpu)
18+
* [`fn siToBytes(str)`](#fn-sitobytes)
19+
20+
## Fields
21+
22+
### fn formatDuration
23+
24+
```ts
25+
formatDuration(seconds)
26+
```
27+
28+
`formatDuration` formats a number of seconds into a human-readable duration string.
29+
Returns the duration in the smallest appropriate unit (s, m, h, or combined formats like "4m30s").
30+
31+
32+
### fn parseDuration
33+
34+
```ts
35+
parseDuration(duration)
36+
```
37+
38+
`parseDuration` parses a duration string and returns the number of seconds.
39+
Handles milliseconds (ms), seconds (s), minutes (m), hours (h), and combined formats like "4m30s" or "1h30m".
40+
41+
42+
### fn parseKubernetesCPU
43+
44+
```ts
45+
parseKubernetesCPU(input)
46+
```
47+
48+
`parseKubernetesCPU` parses a Kubernetes CPU string/number into a number of cores.
49+
The function assumes the input is in a correct Kubernetes format, i.e., an integer, a float,
50+
a string representation of an integer or a float, or a string containing a number ending with 'm'
51+
representing a number of millicores.
52+
53+
54+
### fn siToBytes
55+
56+
```ts
57+
siToBytes(str)
58+
```
59+
60+
`siToBytes` converts Kubernetes byte units to bytes.
61+
Only works for limited set of SI prefixes: Ki, Mi, Gi, Ti.

main.libsonnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet';
2121
jsonpath: (import './jsonpath.libsonnet'),
2222
number: (import './number.libsonnet'),
2323
string: (import './string.libsonnet'),
24+
units: (import './units.libsonnet'),
2425
url: (import './url.libsonnet'),
2526
}

test/units_test.jsonnet

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
local units = import '../units.libsonnet';
2+
local test = import 'github.com/jsonnet-libs/testonnet/main.libsonnet';
3+
4+
test.new(std.thisFile)
5+
// parseCPU(10) = parseCPU("10") = 10
6+
// parseCPU(4.5) = parse("4.5") = 4.5
7+
// parseCPU("3000m") = 3000 / 1000
8+
// parseCPU("3580m") = 3580 / 1000
9+
// parseCPU("3980.7m") = 3980.7 / 1000
10+
// parseCPU(0.5) = parse("0.5") = parse("500m") = 0.5
11+
+ test.case.new(
12+
name='parseCPU - integer',
13+
test=test.expect.eq(
14+
actual=units.parseKubernetesCPU(10),
15+
expected=10,
16+
)
17+
)
18+
+ test.case.new(
19+
name='parseCPU - string integer',
20+
test=test.expect.eq(
21+
actual=units.parseKubernetesCPU('10'),
22+
expected=10,
23+
)
24+
)
25+
+ test.case.new(
26+
name='parseCPU - float',
27+
test=test.expect.eq(
28+
actual=units.parseKubernetesCPU(4.5),
29+
expected=4.5,
30+
)
31+
)
32+
+ test.case.new(
33+
name='parseCPU - string float',
34+
test=test.expect.eq(
35+
actual=units.parseKubernetesCPU('4.5'),
36+
expected=4.5,
37+
)
38+
)
39+
+ test.case.new(
40+
name='parseCPU - string millicores',
41+
test=test.expect.eq(
42+
actual=units.parseKubernetesCPU('3000m'),
43+
expected=3,
44+
)
45+
)
46+
+ test.case.new(
47+
name='parseCPU - string millicores',
48+
test=test.expect.eq(
49+
actual=units.parseKubernetesCPU('3580m'),
50+
expected=3.58,
51+
)
52+
)
53+
+ test.case.new(
54+
name='parseCPU - string millicores',
55+
test=test.expect.eq(
56+
actual=units.parseKubernetesCPU('3980.7m'),
57+
expected=3980.7 / 1000, // Use a division to avoid floating point precision issues
58+
)
59+
)
60+
+ test.case.new(
61+
name='parseCPU - fraction',
62+
test=test.expect.eq(
63+
actual=units.parseKubernetesCPU(0.5),
64+
expected=0.5,
65+
)
66+
)
67+
+ test.case.new(
68+
name='parseCPU - string fraction',
69+
test=test.expect.eq(
70+
actual=units.parseKubernetesCPU('0.5'),
71+
expected=0.5,
72+
)
73+
)
74+
+ test.case.new(
75+
name='parseCPU - fraction millicores',
76+
test=test.expect.eq(
77+
actual=units.parseKubernetesCPU('500m'),
78+
expected=0.5,
79+
)
80+
)
81+
82+
// siToBytes tests
83+
+ test.case.new(
84+
name='siToBytes - plain number',
85+
test=test.expect.eq(
86+
actual=units.siToBytes('1024'),
87+
expected=1024,
88+
)
89+
)
90+
+ test.case.new(
91+
name='siToBytes - Ki',
92+
test=test.expect.eq(
93+
actual=units.siToBytes('1Ki'),
94+
expected=1024,
95+
)
96+
)
97+
+ test.case.new(
98+
name='siToBytes - Mi',
99+
test=test.expect.eq(
100+
actual=units.siToBytes('1Mi'),
101+
expected=1048576,
102+
)
103+
)
104+
+ test.case.new(
105+
name='siToBytes - Gi',
106+
test=test.expect.eq(
107+
actual=units.siToBytes('2Gi'),
108+
expected=2147483648,
109+
)
110+
)
111+
+ test.case.new(
112+
name='siToBytes - Ti',
113+
test=test.expect.eq(
114+
actual=units.siToBytes('1Ti'),
115+
expected=1099511627776,
116+
)
117+
)
118+
+ test.case.new(
119+
name='siToBytes - fractional Ki',
120+
test=test.expect.eq(
121+
actual=units.siToBytes('1.5Ki'),
122+
expected=1536,
123+
)
124+
)
125+
126+
// parseDuration tests
127+
+ test.case.new(
128+
name='parseDuration - milliseconds',
129+
test=test.expect.eq(
130+
actual=units.parseDuration('500ms'),
131+
expected=0.5,
132+
)
133+
)
134+
+ test.case.new(
135+
name='parseDuration - seconds',
136+
test=test.expect.eq(
137+
actual=units.parseDuration('30s'),
138+
expected=30,
139+
)
140+
)
141+
+ test.case.new(
142+
name='parseDuration - minutes',
143+
test=test.expect.eq(
144+
actual=units.parseDuration('5m'),
145+
expected=300,
146+
)
147+
)
148+
+ test.case.new(
149+
name='parseDuration - hours',
150+
test=test.expect.eq(
151+
actual=units.parseDuration('2h'),
152+
expected=7200,
153+
)
154+
)
155+
+ test.case.new(
156+
name='parseDuration - combined minutes and seconds',
157+
test=test.expect.eq(
158+
actual=units.parseDuration('4m30s'),
159+
expected=270,
160+
)
161+
)
162+
+ test.case.new(
163+
name='parseDuration - combined hours and fractional seconds',
164+
test=test.expect.eq(
165+
actual=units.parseDuration('1h30.5s'),
166+
expected=3600 + 30.5,
167+
)
168+
)
169+
+ test.case.new(
170+
name='parseDuration - combined hours and minutes',
171+
test=test.expect.eq(
172+
actual=units.parseDuration('1h30m'),
173+
expected=5400,
174+
)
175+
)
176+
+ test.case.new(
177+
name='parseDuration - combined hours and milliseconds',
178+
test=test.expect.eq(
179+
actual=units.parseDuration('1h500ms'),
180+
expected=3600 + 0.5,
181+
)
182+
)
183+
184+
// formatDuration tests
185+
+ test.case.new(
186+
name='formatDuration - milliseconds',
187+
test=test.expect.eq(
188+
actual=units.formatDuration(0.5),
189+
expected='500ms',
190+
)
191+
)
192+
+ test.case.new(
193+
name='formatDuration - seconds',
194+
test=test.expect.eq(
195+
actual=units.formatDuration(45),
196+
expected='45s',
197+
)
198+
)
199+
+ test.case.new(
200+
name='formatDuration - minutes',
201+
test=test.expect.eq(
202+
actual=units.formatDuration(300),
203+
expected='5m',
204+
)
205+
)
206+
+ test.case.new(
207+
name='formatDuration - hours',
208+
test=test.expect.eq(
209+
actual=units.formatDuration(7200),
210+
expected='2h',
211+
)
212+
)
213+
+ test.case.new(
214+
name='formatDuration - combined minutes and seconds',
215+
test=test.expect.eq(
216+
actual=units.formatDuration(270),
217+
expected='4m30s',
218+
)
219+
)
220+
+ test.case.new(
221+
name='formatDuration - combined hours and minutes',
222+
test=test.expect.eq(
223+
actual=units.formatDuration(5400),
224+
expected='1h30m',
225+
)
226+
)
227+
+ test.case.new(
228+
name='formatDuration - combined hours and minutes and seconds',
229+
test=test.expect.eq(
230+
actual=units.formatDuration(5400 + 30),
231+
expected='1h30m30s',
232+
)
233+
)
234+
+ test.case.new(
235+
name='formatDuration - combined hours and minutes and seconds and milliseconds',
236+
test=test.expect.eq(
237+
actual=units.formatDuration(5400 + 30 + 0.5),
238+
expected='1h30m30s500ms',
239+
)
240+
)
241+
242+
+ test.case.new(
243+
name='formatDuration - combined hours and milliseconds',
244+
test=test.expect.eq(
245+
actual=units.formatDuration(3600 + 0.5),
246+
expected='1h500ms',
247+
)
248+
)

0 commit comments

Comments
 (0)