@quenty/metricutils 2.4.3 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -54
- package/README.md +80 -2
- package/deploy.nevermore.json +10 -0
- package/package.json +22 -4
- package/src/Shared/Definitions/MetricUnitDefinitions.lua +1082 -0
- package/src/Shared/Definitions/MetricUnitDefinitions.spec.lua +55 -0
- package/src/Shared/Definitions/MetricUnitDimensionUtils.lua +164 -0
- package/src/Shared/Definitions/MetricUnitDimensionUtils.spec.lua +49 -0
- package/src/Shared/Definitions/MetricUnitKinds.lua +237 -0
- package/src/Shared/Definitions/MetricUnitKinds.spec.lua +51 -0
- package/src/Shared/Formatting/MetricUnitDisplayUnitUtils.lua +129 -0
- package/src/Shared/Formatting/MetricUnitFormatUtils.lua +924 -0
- package/src/Shared/Formatting/MetricUnitFormatUtils.spec.lua +280 -0
- package/src/Shared/Formatting/RxMetricUnitFormatUtils.lua +62 -0
- package/src/Shared/Localization/MetricUnitFallbackStrings.lua +289 -0
- package/src/Shared/Localization/MetricUnitFallbackStrings.spec.lua +82 -0
- package/src/Shared/Localization/MetricUnitTranslator/ar.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/de.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/en.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/es.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/fr.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/id.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/init.lua +92 -0
- package/src/Shared/Localization/MetricUnitTranslator/it.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/ja.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/ko.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/pl.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/pt.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/ru.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/th.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/tr.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/vi.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/zh-cn.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator/zh-tw.json.txt +182 -0
- package/src/Shared/Localization/MetricUnitTranslator.spec.lua +309 -0
- package/src/Shared/Localization/PluralCategoryUtils.lua +103 -0
- package/src/Shared/Localization/PluralCategoryUtils.spec.lua +77 -0
- package/src/Shared/Logarithmic/DecibelUtils.lua +72 -0
- package/src/Shared/Logarithmic/DecibelUtils.spec.lua +35 -0
- package/src/Shared/MetricUnit.Angles.spec.lua +80 -0
- package/src/Shared/MetricUnit.Customary.spec.lua +104 -0
- package/src/Shared/MetricUnit.Derived.spec.lua +173 -0
- package/src/Shared/MetricUnit.Display.spec.lua +153 -0
- package/src/Shared/MetricUnit.Electrical.spec.lua +114 -0
- package/src/Shared/MetricUnit.Math.spec.lua +112 -0
- package/src/Shared/MetricUnit.Roblox.spec.lua +34 -0
- package/src/Shared/MetricUnit.SI.spec.lua +127 -0
- package/src/Shared/MetricUnit.Spring.spec.lua +94 -0
- package/src/Shared/MetricUnit.Temperature.spec.lua +212 -0
- package/src/Shared/MetricUnit.Time.spec.lua +202 -0
- package/src/Shared/MetricUnit.Units.spec.lua +210 -0
- package/src/Shared/MetricUnit.lua +1730 -0
- package/src/Shared/MetricUnit.spec.lua +362 -0
- package/src/Shared/MetricUtils.lua +47 -16
- package/src/Shared/MetricUtils.spec.lua +76 -0
- package/src/Shared/Parsing/MetricUnitParseUtils.lua +799 -0
- package/src/Shared/Parsing/MetricUnitParseUtils.spec.lua +189 -0
- package/src/Shared/Systems/MetricUnitSystem.lua +322 -0
- package/src/Shared/Systems/MetricUnitSystem.spec.lua +181 -0
- package/src/Shared/Systems/MetricUnitSystems.lua +225 -0
- package/src/jest.config.lua +3 -0
- package/src/node_modules.project.json +7 -0
- package/test/default.project.json +25 -0
- package/test/scripts/Server/ServerMain.server.lua +14 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class MetricUnit.Temperature.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local Jest = require("Jest")
|
|
9
|
+
local MetricUnit = require("MetricUnit")
|
|
10
|
+
|
|
11
|
+
local DAY = MetricUnit.days(1):InSeconds()
|
|
12
|
+
local YEAR = MetricUnit.years(1):InSeconds()
|
|
13
|
+
|
|
14
|
+
local describe = Jest.Globals.describe
|
|
15
|
+
local expect = Jest.Globals.expect
|
|
16
|
+
local it = Jest.Globals.it
|
|
17
|
+
|
|
18
|
+
local function format(value: any): string
|
|
19
|
+
return (string.gsub(MetricUnit.format(value), "\u{00A0}", " "))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe("MetricUnit absolute temperatures", function()
|
|
23
|
+
it("reads each scale back from its own zero", function()
|
|
24
|
+
expect(MetricUnit.celsius(5):In("celsius")).toBeCloseTo(5, 9)
|
|
25
|
+
expect(MetricUnit.celsius(5):In("kelvin")).toBeCloseTo(278.15, 9)
|
|
26
|
+
expect(MetricUnit.kelvin(0):In("celsius")).toBeCloseTo(-273.15, 9)
|
|
27
|
+
expect(MetricUnit.fahrenheit(212):In("celsius")).toBeCloseTo(100, 9)
|
|
28
|
+
expect(MetricUnit.celsius(-40):In("fahrenheit")).toBeCloseTo(-40, 9)
|
|
29
|
+
expect(MetricUnit.fahrenheit(32):In("fahrenheit")).toBeCloseTo(32, 9)
|
|
30
|
+
expect(MetricUnit.isKind(MetricUnit.kelvin(300), "temperature")).toBe(true)
|
|
31
|
+
expect((MetricUnit.celsius(5)):IsAbsolute()).toBe(true)
|
|
32
|
+
end)
|
|
33
|
+
|
|
34
|
+
it("subtracts two absolutes to a difference", function()
|
|
35
|
+
local difference = MetricUnit.celsius(5) - MetricUnit.celsius(2)
|
|
36
|
+
expect(MetricUnit.isKind(difference, "temperatureDifference")).toBe(true)
|
|
37
|
+
expect((difference):IsAbsolute()).toBe(false)
|
|
38
|
+
expect(difference:In("kelvin")).toBeCloseTo(3, 9)
|
|
39
|
+
expect(difference:In("celsius")).toBeCloseTo(3, 9)
|
|
40
|
+
expect(difference:In("fahrenheit")).toBeCloseTo(5.4, 9)
|
|
41
|
+
end)
|
|
42
|
+
|
|
43
|
+
it("adds a difference to an absolute, on either side, to an absolute", function()
|
|
44
|
+
local swing = MetricUnit.difference(12, "celsius")
|
|
45
|
+
expect((MetricUnit.celsius(15) + swing):In("celsius")).toBeCloseTo(27, 9)
|
|
46
|
+
expect((swing + MetricUnit.celsius(15)):In("celsius")).toBeCloseTo(27, 9)
|
|
47
|
+
expect((MetricUnit.celsius(15) - swing):In("celsius")).toBeCloseTo(3, 9)
|
|
48
|
+
expect(MetricUnit.isKind(MetricUnit.celsius(15) - swing, "temperature")).toBe(true)
|
|
49
|
+
expect((MetricUnit.celsius(15) + 0):In("celsius")).toBeCloseTo(15, 9)
|
|
50
|
+
end)
|
|
51
|
+
|
|
52
|
+
it("errors adding two absolutes", function()
|
|
53
|
+
expect(function()
|
|
54
|
+
local _ = MetricUnit.celsius(5) + MetricUnit.celsius(2)
|
|
55
|
+
end).toThrow(
|
|
56
|
+
"cannot add two absolute temperatures; subtract them for a difference, or add a difference to one"
|
|
57
|
+
)
|
|
58
|
+
end)
|
|
59
|
+
|
|
60
|
+
it("errors subtracting an absolute from a difference", function()
|
|
61
|
+
expect(function()
|
|
62
|
+
local _ = MetricUnit.difference(5, "celsius") - MetricUnit.celsius(2)
|
|
63
|
+
end).toThrow("cannot subtract an absolute temperature from a temperature difference")
|
|
64
|
+
expect(function()
|
|
65
|
+
local _ = 0 - MetricUnit.celsius(2)
|
|
66
|
+
end).toThrow("cannot subtract an absolute temperature from a temperature difference")
|
|
67
|
+
end)
|
|
68
|
+
|
|
69
|
+
it("errors scaling, negating or taking powers of an absolute, kelvin included", function()
|
|
70
|
+
expect(function()
|
|
71
|
+
local _ = MetricUnit.celsius(5) * 2
|
|
72
|
+
end).toThrow("cannot multiply an absolute temperature")
|
|
73
|
+
expect(function()
|
|
74
|
+
local _ = 2 * MetricUnit.kelvin(300)
|
|
75
|
+
end).toThrow("cannot multiply an absolute temperature")
|
|
76
|
+
expect(function()
|
|
77
|
+
local _ = MetricUnit.kelvin(300) / MetricUnit.seconds(1)
|
|
78
|
+
end).toThrow("cannot divide an absolute temperature")
|
|
79
|
+
expect(function()
|
|
80
|
+
local _ = -MetricUnit.celsius(5)
|
|
81
|
+
end).toThrow("cannot negate an absolute temperature")
|
|
82
|
+
expect(function()
|
|
83
|
+
MetricUnit.abs(MetricUnit.celsius(5))
|
|
84
|
+
end).toThrow("cannot take the size of an absolute temperature")
|
|
85
|
+
expect(function()
|
|
86
|
+
MetricUnit.pow(MetricUnit.celsius(5), 2)
|
|
87
|
+
end).toThrow("cannot exponentiate an absolute temperature")
|
|
88
|
+
end)
|
|
89
|
+
|
|
90
|
+
it("errors reading an absolute with In or a non-temperature reader", function()
|
|
91
|
+
expect(function()
|
|
92
|
+
MetricUnit.celsius(5):In(MetricUnit.difference(1, "kelvin"))
|
|
93
|
+
end).toThrow("cannot take the ratio of an absolute temperature")
|
|
94
|
+
expect(function()
|
|
95
|
+
MetricUnit.celsius(5):In("day")
|
|
96
|
+
end).toThrow('In("day") reads time, not absolute temperature')
|
|
97
|
+
expect(function()
|
|
98
|
+
MetricUnit.kilometers(5):In("celsius")
|
|
99
|
+
end).toThrow('In("celsius") reads temperature, not length')
|
|
100
|
+
end)
|
|
101
|
+
end)
|
|
102
|
+
|
|
103
|
+
describe("MetricUnit temperature differences", function()
|
|
104
|
+
it("makes differences on each scale", function()
|
|
105
|
+
expect(MetricUnit.difference(3, "kelvin"):In("kelvin")).toBe(3)
|
|
106
|
+
expect(MetricUnit.difference(3, "celsius"):In("kelvin")).toBe(3)
|
|
107
|
+
expect(MetricUnit.difference(9, "fahrenheit"):In("celsius")).toBeCloseTo(5, 9)
|
|
108
|
+
expect(MetricUnit.isKind(MetricUnit.difference(1, "celsius"), "temperatureDifference")).toBe(true)
|
|
109
|
+
expect(MetricUnit.isKind(MetricUnit.difference(1, "celsius"), "temperature")).toBe(false)
|
|
110
|
+
end)
|
|
111
|
+
|
|
112
|
+
it("scales, negates and divides freely", function()
|
|
113
|
+
local swing = MetricUnit.difference(12, "celsius")
|
|
114
|
+
expect((swing * 0.5):In("celsius")).toBeCloseTo(6, 9)
|
|
115
|
+
expect((-swing):In("celsius")).toBeCloseTo(-12, 9)
|
|
116
|
+
expect((swing / MetricUnit.years(1)):In(MetricUnit.difference(1, "kelvin") / MetricUnit.days(1))).toBeCloseTo(
|
|
117
|
+
12 * DAY / YEAR,
|
|
118
|
+
12
|
|
119
|
+
)
|
|
120
|
+
end)
|
|
121
|
+
end)
|
|
122
|
+
|
|
123
|
+
describe("MetricUnit temperature comparisons", function()
|
|
124
|
+
it("compares two absolutes or two differences", function()
|
|
125
|
+
expect(MetricUnit.celsius(5) < MetricUnit.celsius(6)).toBe(true)
|
|
126
|
+
expect(MetricUnit.celsius(5) == MetricUnit.kelvin(278.15)).toBe(true)
|
|
127
|
+
expect(MetricUnit.fuzzyEq(MetricUnit.fahrenheit(32), MetricUnit.celsius(0))).toBe(true)
|
|
128
|
+
expect(MetricUnit.difference(1, "celsius") <= MetricUnit.difference(2, "fahrenheit")).toBe(true)
|
|
129
|
+
expect(MetricUnit.max(MetricUnit.celsius(5), MetricUnit.celsius(9)):In("celsius")).toBeCloseTo(9, 9)
|
|
130
|
+
expect(MetricUnit.isKind(MetricUnit.max(MetricUnit.celsius(5), MetricUnit.celsius(9)), "temperature")).toBe(
|
|
131
|
+
true
|
|
132
|
+
)
|
|
133
|
+
end)
|
|
134
|
+
|
|
135
|
+
it("errors comparing an absolute with a difference", function()
|
|
136
|
+
expect(function()
|
|
137
|
+
local _ = MetricUnit.celsius(5) < MetricUnit.difference(6, "celsius")
|
|
138
|
+
end).toThrow("cannot compare an absolute temperature and a temperature difference")
|
|
139
|
+
expect(function()
|
|
140
|
+
local _ = MetricUnit.celsius(5) == MetricUnit.difference(5, "kelvin")
|
|
141
|
+
end).toThrow("cannot compare an absolute temperature and a temperature difference")
|
|
142
|
+
expect(function()
|
|
143
|
+
MetricUnit.max(MetricUnit.celsius(5), 0)
|
|
144
|
+
end).toThrow("cannot compare absolute temperature and the plain number 0")
|
|
145
|
+
end)
|
|
146
|
+
end)
|
|
147
|
+
|
|
148
|
+
describe("MetricUnit temperature boundaries and data", function()
|
|
149
|
+
it("expects an absolute temperature or a difference by name", function()
|
|
150
|
+
expect(MetricUnit.expect(MetricUnit.celsius(5), "temperature", "air")).toBeCloseTo(278.15, 9)
|
|
151
|
+
expect(MetricUnit.expect(MetricUnit.difference(12, "celsius"), "temperatureDifference", "swing")).toBe(12)
|
|
152
|
+
expect(MetricUnit.expect(0, "temperatureDifference", "swing")).toBe(0)
|
|
153
|
+
expect(function()
|
|
154
|
+
MetricUnit.expect(MetricUnit.difference(12, "celsius"), "temperature", "air")
|
|
155
|
+
end).toThrow("MetricUnit.expect: air expects absolute temperature, got temperature difference")
|
|
156
|
+
expect(function()
|
|
157
|
+
MetricUnit.expect(MetricUnit.celsius(12), "temperatureDifference", "swing")
|
|
158
|
+
end).toThrow("MetricUnit.expect: swing expects temperature difference, got absolute temperature")
|
|
159
|
+
expect(function()
|
|
160
|
+
MetricUnit.expect(0, "temperature", "air")
|
|
161
|
+
end).toThrow("MetricUnit.expect: air expects absolute temperature, got the plain number 0")
|
|
162
|
+
end)
|
|
163
|
+
|
|
164
|
+
it("round trips an absolute through plain data", function()
|
|
165
|
+
local data = MetricUnit.toData(MetricUnit.kelvin(300))
|
|
166
|
+
expect(data).toEqual({ amount = 300, dimensions = { temperature = 1 }, absolute = true })
|
|
167
|
+
local back = MetricUnit.fromData(data)
|
|
168
|
+
expect(MetricUnit.isKind(back, "temperature")).toBe(true)
|
|
169
|
+
expect(back:In("kelvin")).toBe(300)
|
|
170
|
+
expect(MetricUnit.toData(MetricUnit.difference(3, "kelvin"))).toEqual({
|
|
171
|
+
amount = 3,
|
|
172
|
+
dimensions = { temperature = 1 },
|
|
173
|
+
})
|
|
174
|
+
end)
|
|
175
|
+
end)
|
|
176
|
+
|
|
177
|
+
describe("MetricUnit.point and MetricUnit.difference", function()
|
|
178
|
+
it("makes a point from a unit's zero, in any unit", function()
|
|
179
|
+
expect(MetricUnit.point(20, "celsius") == MetricUnit.celsius(20)).toBe(true)
|
|
180
|
+
expect(MetricUnit.point(90, "second") == MetricUnit.instant(90)).toBe(true)
|
|
181
|
+
expect(MetricUnit.point(1.5, "minute"):In("second")).toBe(90)
|
|
182
|
+
expect(MetricUnit.point(5, "meter"):IsAbsolute()).toBe(true)
|
|
183
|
+
end)
|
|
184
|
+
|
|
185
|
+
it("makes a difference, in any unit", function()
|
|
186
|
+
expect(MetricUnit.difference(9, "fahrenheit"):In("kelvin")).toBeCloseTo(5, 9)
|
|
187
|
+
expect(MetricUnit.difference(12, "celsius"):IsAbsolute()).toBe(false)
|
|
188
|
+
expect(MetricUnit.difference(5, "meter") == MetricUnit.meters(5)).toBe(true)
|
|
189
|
+
end)
|
|
190
|
+
|
|
191
|
+
it("follows the point rules for every dimension", function()
|
|
192
|
+
local gap = MetricUnit.point(7, "meter") - MetricUnit.point(2, "meter")
|
|
193
|
+
expect(gap == MetricUnit.meters(5)).toBe(true)
|
|
194
|
+
expect(function()
|
|
195
|
+
local _ = MetricUnit.point(7, "meter") + MetricUnit.point(2, "meter")
|
|
196
|
+
end).toThrow()
|
|
197
|
+
end)
|
|
198
|
+
|
|
199
|
+
it("formats a point on the scale people read and a difference in kelvin", function()
|
|
200
|
+
expect(format(MetricUnit.point(20, "celsius"))).toBe("20 °C")
|
|
201
|
+
expect(format(MetricUnit.difference(20, "celsius"))).toBe("20 K")
|
|
202
|
+
end)
|
|
203
|
+
|
|
204
|
+
it("errors on an unknown unit or a non-number", function()
|
|
205
|
+
expect(function()
|
|
206
|
+
MetricUnit.point(1, "klicks" :: any)
|
|
207
|
+
end).toThrow('MetricUnit.point knows no unit "klicks"')
|
|
208
|
+
expect(function()
|
|
209
|
+
MetricUnit.difference("1" :: any, "meter")
|
|
210
|
+
end).toThrow("MetricUnit.difference takes a number")
|
|
211
|
+
end)
|
|
212
|
+
end)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class MetricUnit.Time.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local Jest = require("Jest")
|
|
9
|
+
local MetricUnit = require("MetricUnit")
|
|
10
|
+
local TimeDurationUtils = require("TimeDurationUtils")
|
|
11
|
+
local TimeLocalizationUtils = require("TimeLocalizationUtils")
|
|
12
|
+
|
|
13
|
+
local MONTH = MetricUnit.months(1):InSeconds()
|
|
14
|
+
local YEAR = MetricUnit.years(1):InSeconds()
|
|
15
|
+
|
|
16
|
+
local describe = Jest.Globals.describe
|
|
17
|
+
local expect = Jest.Globals.expect
|
|
18
|
+
local it = Jest.Globals.it
|
|
19
|
+
|
|
20
|
+
-- Formatting puts a no-break space between a number and its unit; these compare it as a plain space
|
|
21
|
+
local function plain(text: string): string
|
|
22
|
+
return (string.gsub(text, "\u{00A0}", " "))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
local function format(value: any, options: MetricUnit.FormatOptions?): string
|
|
26
|
+
return plain(MetricUnit.format(value, options))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe("MetricUnit.format durations", function()
|
|
30
|
+
it("writes averaged years and months whole", function()
|
|
31
|
+
expect(format(MetricUnit.years(1))).toBe("1 year")
|
|
32
|
+
expect(format(MetricUnit.months(1))).toBe("1 month")
|
|
33
|
+
expect(format(MetricUnit.years(1) / 12)).toBe("1 month")
|
|
34
|
+
expect(format(MetricUnit.months(12))).toBe("1 year")
|
|
35
|
+
expect(format(MetricUnit.years(100))).toBe("100 years")
|
|
36
|
+
expect(format(MetricUnit.years(1) + MetricUnit.days(1))).toBe("1 year, 1 day")
|
|
37
|
+
end)
|
|
38
|
+
|
|
39
|
+
it("breaks a duration into its two largest units", function()
|
|
40
|
+
expect(format(MetricUnit.minutes(90))).toBe("1 hour, 30 minutes")
|
|
41
|
+
expect(format(MetricUnit.days(1.5))).toBe("1 day, 12 hours")
|
|
42
|
+
expect(format(MetricUnit.hours(36.6))).toBe("1 day, 13 hours")
|
|
43
|
+
expect(format(MetricUnit.seconds(45))).toBe("45 seconds")
|
|
44
|
+
expect(format(MetricUnit.years(1234))).toBe("1,234 years")
|
|
45
|
+
end)
|
|
46
|
+
|
|
47
|
+
it("carries a rounded unit into the next larger one", function()
|
|
48
|
+
expect(format(MetricUnit.days(1) + MetricUnit.hours(23) + MetricUnit.minutes(59.7))).toBe("2 days")
|
|
49
|
+
expect(format(MetricUnit.minutes(59.9), { maxParts = 1 })).toBe("1 hour")
|
|
50
|
+
end)
|
|
51
|
+
|
|
52
|
+
it("takes how many units to show and the separator", function()
|
|
53
|
+
expect(format(MetricUnit.minutes(90), { maxParts = 1 })).toBe("2 hours")
|
|
54
|
+
expect(format(MetricUnit.days(1) + MetricUnit.hours(2) + MetricUnit.minutes(3), { maxParts = 3 })).toBe(
|
|
55
|
+
"1 day, 2 hours, 3 minutes"
|
|
56
|
+
)
|
|
57
|
+
expect(format(MetricUnit.minutes(90), { separator = " " })).toBe("1 hour 30 minutes")
|
|
58
|
+
end)
|
|
59
|
+
|
|
60
|
+
it("writes zero, milliseconds and less than a millisecond", function()
|
|
61
|
+
expect(format(MetricUnit.seconds(0))).toBe("0 seconds")
|
|
62
|
+
expect(format(MetricUnit.milliseconds(250))).toBe("250 milliseconds")
|
|
63
|
+
expect(format(MetricUnit.new(40, "microsecond"))).toBe("40 microseconds")
|
|
64
|
+
end)
|
|
65
|
+
|
|
66
|
+
it("signs a negative duration once", function()
|
|
67
|
+
expect(format(-MetricUnit.minutes(90))).toBe("-1 hour, 30 minutes")
|
|
68
|
+
end)
|
|
69
|
+
|
|
70
|
+
it("writes one fixed time unit with a fractional amount", function()
|
|
71
|
+
expect(format(MetricUnit.minutes(90), { unit = "hour" })).toBe("1.5 hours")
|
|
72
|
+
expect(format(MetricUnit.hours(1), { unit = "hour" })).toBe("1 hour")
|
|
73
|
+
expect(format(MetricUnit.hours(36), { unit = "day", locale = "es-es" })).toBe("1,5 días")
|
|
74
|
+
end)
|
|
75
|
+
|
|
76
|
+
it("uses @quenty/time's localized duration words", function()
|
|
77
|
+
expect(format(MetricUnit.minutes(90), { locale = "es-es" })).toBe("1 hora, 30 minutos")
|
|
78
|
+
expect(format(MetricUnit.days(2), { locale = "fr-fr" })).toBe("2 jours")
|
|
79
|
+
expect(format(MetricUnit.hours(2), { locale = "ru-ru" })).toBe("2 часа")
|
|
80
|
+
local hours: TimeLocalizationUtils.DurationPhrase = { one = "%d hr", other = "%d hrs" }
|
|
81
|
+
expect(format(MetricUnit.minutes(90), { durationStrings = { hours = hours } })).toBe("1 hr, 30 minutes")
|
|
82
|
+
end)
|
|
83
|
+
end)
|
|
84
|
+
|
|
85
|
+
describe("MetricUnit.format clock durations", function()
|
|
86
|
+
it("writes a clock, minutes and seconds under an hour", function()
|
|
87
|
+
expect(format(MetricUnit.minutes(90), { durationStyle = "clock" })).toBe("1:30:00")
|
|
88
|
+
expect(format(MetricUnit.seconds(45), { durationStyle = "clock" })).toBe("0:45")
|
|
89
|
+
expect(format(MetricUnit.seconds(3725), { durationStyle = "clock" })).toBe("1:02:05")
|
|
90
|
+
expect(format(MetricUnit.hours(30), { durationStyle = "clock" })).toBe("30:00:00")
|
|
91
|
+
end)
|
|
92
|
+
|
|
93
|
+
it("passes a template to TimeDurationUtils, refusing years and months", function()
|
|
94
|
+
expect(format(MetricUnit.seconds(90), { durationTemplate = "mm:ss" })).toBe("01:30")
|
|
95
|
+
expect(format(MetricUnit.days(2), { durationTemplate = "d __" })).toBe("2 days")
|
|
96
|
+
expect(format(MetricUnit.seconds(90), { durationTemplate = "[at] m:ss" })).toBe("at 1:30")
|
|
97
|
+
expect(function()
|
|
98
|
+
format(MetricUnit.years(1), { durationTemplate = "y __" })
|
|
99
|
+
end).toThrow("counts years or months")
|
|
100
|
+
end)
|
|
101
|
+
end)
|
|
102
|
+
|
|
103
|
+
describe("MetricUnit and @quenty/time", function()
|
|
104
|
+
it("hands exact seconds to TimeDurationUtils", function()
|
|
105
|
+
expect(MetricUnit.minutes(2):InSeconds()).toBe(120)
|
|
106
|
+
expect(TimeDurationUtils.format(MetricUnit.hours(36):InSeconds(), "h:mm")).toBe("36:00")
|
|
107
|
+
expect(MetricUnit.years(1):InSeconds()).toBe(YEAR)
|
|
108
|
+
end)
|
|
109
|
+
|
|
110
|
+
it("measures the exact time between two DateTimes", function()
|
|
111
|
+
local start = MetricUnit.fromDateTime(DateTime.fromUnixTimestamp(0))
|
|
112
|
+
local later = MetricUnit.fromDateTime(DateTime.fromUnixTimestamp(90))
|
|
113
|
+
expect((later - start):InSeconds()).toBe(90)
|
|
114
|
+
expect((start - later):InSeconds()).toBe(-90)
|
|
115
|
+
expect(MetricUnit.isKind(later - start, "time")).toBe(true)
|
|
116
|
+
|
|
117
|
+
-- A calendar year with a leap day is 366 days, longer than the averaged year
|
|
118
|
+
local leapYear = MetricUnit.fromDateTime(DateTime.fromUniversalTime(2025, 1, 1))
|
|
119
|
+
- MetricUnit.fromDateTime(DateTime.fromUniversalTime(2024, 1, 1))
|
|
120
|
+
expect(leapYear:In("day")).toBe(366)
|
|
121
|
+
expect(leapYear > MetricUnit.years(1)).toBe(true)
|
|
122
|
+
end)
|
|
123
|
+
|
|
124
|
+
it("moves a DateTime by an exact span", function()
|
|
125
|
+
local start = MetricUnit.fromDateTime(DateTime.fromUnixTimestamp(0))
|
|
126
|
+
expect((start + MetricUnit.hours(1)):ToDateTime().UnixTimestamp).toBe(3600)
|
|
127
|
+
expect((start + MetricUnit.months(1)):ToDateTime().UnixTimestampMillis).toBe(MONTH * 1000)
|
|
128
|
+
end)
|
|
129
|
+
end)
|
|
130
|
+
|
|
131
|
+
describe("MetricUnit instants", function()
|
|
132
|
+
it("subtracts two instants to a span, and adds a span to an instant", function()
|
|
133
|
+
local worldStart = MetricUnit.instant(0)
|
|
134
|
+
local now = worldStart + MetricUnit.years(250)
|
|
135
|
+
expect(MetricUnit.isKind(now, "instant")).toBe(true)
|
|
136
|
+
expect(now:IsAbsolute()).toBe(true)
|
|
137
|
+
expect(now:GetKind()).toBe("instant")
|
|
138
|
+
expect((now - worldStart):GetKind()).toBe("time")
|
|
139
|
+
expect((now - worldStart):In("year")).toBeCloseTo(250, 9)
|
|
140
|
+
expect((MetricUnit.years(1) + now - now):In("year")).toBeCloseTo(1, 9)
|
|
141
|
+
expect(MetricUnit.isKind(now - MetricUnit.days(1), "instant")).toBe(true)
|
|
142
|
+
expect(MetricUnit.isKind(now, "time")).toBe(false)
|
|
143
|
+
end)
|
|
144
|
+
|
|
145
|
+
it("reads an instant as the time since its epoch", function()
|
|
146
|
+
local instant = MetricUnit.instant(5400)
|
|
147
|
+
expect(instant:InSeconds()).toBe(5400)
|
|
148
|
+
expect(instant:In("hour")).toBe(1.5)
|
|
149
|
+
expect(function()
|
|
150
|
+
instant:In("meter")
|
|
151
|
+
end).toThrow('In("meter") reads length, not instant')
|
|
152
|
+
end)
|
|
153
|
+
|
|
154
|
+
it("rejects adding, scaling and negating instants", function()
|
|
155
|
+
local instant = MetricUnit.instant(10)
|
|
156
|
+
expect(function()
|
|
157
|
+
local _ = instant + instant
|
|
158
|
+
end).toThrow("cannot add two instants; subtract them for a difference, or add a difference to one")
|
|
159
|
+
expect(function()
|
|
160
|
+
local _ = MetricUnit.seconds(1) - instant
|
|
161
|
+
end).toThrow("cannot subtract an instant from a time")
|
|
162
|
+
expect(function()
|
|
163
|
+
local _ = instant * 2
|
|
164
|
+
end).toThrow("cannot multiply an instant")
|
|
165
|
+
expect(function()
|
|
166
|
+
local _ = -instant
|
|
167
|
+
end).toThrow("cannot negate an instant")
|
|
168
|
+
expect(function()
|
|
169
|
+
MetricUnit.abs(instant)
|
|
170
|
+
end).toThrow("cannot take the size of an instant")
|
|
171
|
+
expect(function()
|
|
172
|
+
local _ = instant < MetricUnit.seconds(20)
|
|
173
|
+
end).toThrow("cannot compare an instant and a time")
|
|
174
|
+
end)
|
|
175
|
+
|
|
176
|
+
it("expects instants and spans apart", function()
|
|
177
|
+
expect(MetricUnit.expect(MetricUnit.instant(7), "instant", "at")).toBe(7)
|
|
178
|
+
expect(function()
|
|
179
|
+
MetricUnit.expect(MetricUnit.seconds(7), "instant", "at")
|
|
180
|
+
end).toThrow("MetricUnit.expect: at expects instant, got time")
|
|
181
|
+
expect(function()
|
|
182
|
+
MetricUnit.expect(MetricUnit.instant(7), "time", "every")
|
|
183
|
+
end).toThrow("MetricUnit.expect: every expects time, got instant")
|
|
184
|
+
end)
|
|
185
|
+
|
|
186
|
+
it("round trips through DateTime and plain data", function()
|
|
187
|
+
local dateTime = DateTime.fromUnixTimestampMillis(1_700_000_000_123)
|
|
188
|
+
expect(MetricUnit.fromDateTime(dateTime):ToDateTime().UnixTimestampMillis).toBe(1_700_000_000_123)
|
|
189
|
+
expect(function()
|
|
190
|
+
MetricUnit.seconds(5):ToDateTime()
|
|
191
|
+
end).toThrow("ToDateTime takes an instant, not time")
|
|
192
|
+
|
|
193
|
+
local data = MetricUnit.toData(MetricUnit.instant(42))
|
|
194
|
+
expect(data).toEqual({ amount = 42, dimensions = { time = 1 }, absolute = true })
|
|
195
|
+
expect(MetricUnit.isKind(MetricUnit.fromData(data), "instant")).toBe(true)
|
|
196
|
+
end)
|
|
197
|
+
|
|
198
|
+
it("writes an instant apart from a span", function()
|
|
199
|
+
expect(tostring(MetricUnit.instant(90))).toBe("epoch + " .. tostring(MetricUnit.seconds(90)))
|
|
200
|
+
expect(format(MetricUnit.instant(5400))).toBe("1 hour, 30 minutes")
|
|
201
|
+
end)
|
|
202
|
+
end)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class MetricUnit.Units.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local Jest = require("Jest")
|
|
9
|
+
local MetricUnit = require("MetricUnit")
|
|
10
|
+
local MetricUnitDefinitions = require("MetricUnitDefinitions")
|
|
11
|
+
local MetricUtils = require("MetricUtils")
|
|
12
|
+
|
|
13
|
+
local describe = Jest.Globals.describe
|
|
14
|
+
local expect = Jest.Globals.expect
|
|
15
|
+
local it = Jest.Globals.it
|
|
16
|
+
|
|
17
|
+
-- Formatting puts a no-break space between a number and its unit; these compare it as a plain space
|
|
18
|
+
local function plain(text: string): string
|
|
19
|
+
return (string.gsub(text, "\u{00A0}", " "))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
local function format(value: any, options: MetricUnit.FormatOptions?): string
|
|
23
|
+
return plain(MetricUnit.format(value, options))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe("MetricUnit:In", function()
|
|
27
|
+
it("reads by unit id, by @quenty/time's names for time, and by unit value", function()
|
|
28
|
+
expect(MetricUnit.kilometers(2):In("meter")).toBe(2000)
|
|
29
|
+
expect(MetricUnit.minutes(90):In("hour")).toBe(1.5)
|
|
30
|
+
expect(MetricUnit.minutes(90):In("hours")).toBe(1.5)
|
|
31
|
+
expect(MetricUnit.minutes(90):In("h")).toBe(1.5)
|
|
32
|
+
expect(MetricUnit.minutes(90):In(MetricUnit.hours(1))).toBe(1.5)
|
|
33
|
+
expect(MetricUnit.perDay(48):In("perHour")).toBeCloseTo(2, 9)
|
|
34
|
+
expect(MetricUnit.years(1):In("quarter")).toBeCloseTo(4, 9)
|
|
35
|
+
end)
|
|
36
|
+
|
|
37
|
+
it("reads a temperature scale from its zero when absolute", function()
|
|
38
|
+
expect(MetricUnit.celsius(100):In("fahrenheit")).toBeCloseTo(212, 9)
|
|
39
|
+
expect(MetricUnit.difference(5, "celsius"):In("fahrenheit")).toBeCloseTo(9, 9)
|
|
40
|
+
end)
|
|
41
|
+
|
|
42
|
+
it("errors on an unknown id, and on another dimension naming both", function()
|
|
43
|
+
expect(function()
|
|
44
|
+
MetricUnit.meters(1):In("klicks" :: any)
|
|
45
|
+
end).toThrow('MetricUnit:In knows no unit "klicks"')
|
|
46
|
+
expect(function()
|
|
47
|
+
MetricUnit.meters(1):In("second")
|
|
48
|
+
end).toThrow('In("second") reads time, not length')
|
|
49
|
+
expect(function()
|
|
50
|
+
MetricUnit.seconds(1):InSeconds()
|
|
51
|
+
end).never.toThrow()
|
|
52
|
+
end)
|
|
53
|
+
end)
|
|
54
|
+
|
|
55
|
+
describe("MetricUnit.new", function()
|
|
56
|
+
it("makes a value from an amount and a unit id", function()
|
|
57
|
+
expect(MetricUnit.new(5, "kilometer") == MetricUnit.kilometers(5)).toBe(true)
|
|
58
|
+
expect(MetricUnit.new(90, "minutes") == MetricUnit.hours(1.5)).toBe(true)
|
|
59
|
+
expect(MetricUnit.new(20, "celsius"):IsAbsolute()).toBe(true)
|
|
60
|
+
expect(function()
|
|
61
|
+
MetricUnit.new(1, "klicks" :: any)
|
|
62
|
+
end).toThrow('MetricUnit.new knows no unit "klicks"')
|
|
63
|
+
end)
|
|
64
|
+
end)
|
|
65
|
+
|
|
66
|
+
describe("MetricUnit dimension queries", function()
|
|
67
|
+
it("names what a value measures", function()
|
|
68
|
+
expect(MetricUnit.kilometers(1):GetKind()).toBe("length")
|
|
69
|
+
expect((MetricUnit.kilometers(1) / MetricUnit.hours(1)):GetKind()).toBe("speed")
|
|
70
|
+
expect(MetricUnit.celsius(5):GetKind()).toBe("temperature")
|
|
71
|
+
expect(MetricUnit.difference(5, "celsius"):GetKind()).toBe("temperatureDifference")
|
|
72
|
+
expect(MetricUnit.none(1):GetKind()).toBe("none")
|
|
73
|
+
expect(MetricUnit.pow(MetricUnit.meters(1), 4):GetKind()).toBeNil()
|
|
74
|
+
end)
|
|
75
|
+
|
|
76
|
+
it("checks kinds by name or exponents, and errors on an unknown name", function()
|
|
77
|
+
local speed = MetricUnit.meters(1) / MetricUnit.seconds(1)
|
|
78
|
+
expect(speed:IsKind("speed")).toBe(true)
|
|
79
|
+
expect(speed:IsKind({ length = 1, time = -1 })).toBe(true)
|
|
80
|
+
expect(MetricUnit.isKind(speed, "length")).toBe(false)
|
|
81
|
+
expect(MetricUnit.isKind(5, "length")).toBe(false)
|
|
82
|
+
expect(function()
|
|
83
|
+
MetricUnit.isKind(speed, "velocity" :: any)
|
|
84
|
+
end).toThrow('no kind named "velocity"')
|
|
85
|
+
end)
|
|
86
|
+
|
|
87
|
+
it("gives the base amount, frozen dimensions and absoluteness", function()
|
|
88
|
+
local length = MetricUnit.kilometers(2)
|
|
89
|
+
expect(length:GetBaseAmount()).toBe(2000)
|
|
90
|
+
expect(length:GetDimensions()).toEqual({ length = 1 })
|
|
91
|
+
expect(table.isfrozen(length:GetDimensions())).toBe(true)
|
|
92
|
+
expect(length:IsAbsolute()).toBe(false)
|
|
93
|
+
end)
|
|
94
|
+
|
|
95
|
+
it("lists the unit ids a value can be read in, metric first", function()
|
|
96
|
+
local ids = MetricUnit.meters(1):GetUnitIds()
|
|
97
|
+
expect(ids[1]).toBe("meter")
|
|
98
|
+
expect(table.find(ids, "nanometer")).never.toBeNil()
|
|
99
|
+
expect(table.find(ids, "mile")).never.toBeNil()
|
|
100
|
+
expect(table.find(ids, "stud")).never.toBeNil()
|
|
101
|
+
expect(table.find(ids, "kilogram")).toBeNil()
|
|
102
|
+
expect(table.find(MetricUnit.celsius(5):GetUnitIds(), "fahrenheit")).never.toBeNil()
|
|
103
|
+
end)
|
|
104
|
+
end)
|
|
105
|
+
|
|
106
|
+
describe("MetricUnit studs", function()
|
|
107
|
+
it("counts a stud as 28 cm, as Roblox documents it", function()
|
|
108
|
+
expect(MetricUnitDefinitions.ROBLOX_METERS_PER_STUD).toBe(0.28)
|
|
109
|
+
expect(MetricUnit.studs(100):In("meter")).toBeCloseTo(28, 9)
|
|
110
|
+
expect(MetricUnit.meters(1):In("stud")).toBeCloseTo(1 / 0.28, 9)
|
|
111
|
+
expect(MetricUnit.new(100, "studPerSecond"):In("meterPerSecond")).toBeCloseTo(28, 9)
|
|
112
|
+
end)
|
|
113
|
+
|
|
114
|
+
it("keeps MetricUtils at the 3.57 studs to the metre it has always used", function()
|
|
115
|
+
expect(MetricUtils.studsToMeters(357)).toBeCloseTo(100, 9)
|
|
116
|
+
expect(MetricUtils.studsPerSecondToMetersPerSecond(35.7)).toBeCloseTo(10, 9)
|
|
117
|
+
end)
|
|
118
|
+
|
|
119
|
+
it("shows studs as studs, until converted", function()
|
|
120
|
+
expect(format(MetricUnit.studs(250))).toBe("250 studs")
|
|
121
|
+
expect(format(MetricUnit.studs(250):ToMetric())).toBe("70 m")
|
|
122
|
+
expect(format(MetricUnit.studs(250), { unit = "stud" })).toBe("250 studs")
|
|
123
|
+
expect(format(MetricUnit.studs(1), { unit = "stud" })).toBe("1 stud")
|
|
124
|
+
expect(format(MetricUnit.new(16, "studPerSecond"), { unit = "studPerSecond" })).toBe("16 studs/s")
|
|
125
|
+
expect(format(MetricUnit.studs(250):ToUSCustomary())).toBe("229.659 ft")
|
|
126
|
+
end)
|
|
127
|
+
end)
|
|
128
|
+
|
|
129
|
+
describe("MetricUnit US customary units", function()
|
|
130
|
+
it("converts with exact definitions", function()
|
|
131
|
+
expect(MetricUnit.new(1, "inch"):In("millimeter")).toBeCloseTo(25.4, 9)
|
|
132
|
+
expect(MetricUnit.fuzzyEq(MetricUnit.new(3, "foot"), MetricUnit.new(1, "yard"))).toBe(true)
|
|
133
|
+
expect(MetricUnit.new(1, "mile"):In("foot")).toBeCloseTo(5280, 9)
|
|
134
|
+
expect(MetricUnit.new(1, "pound"):In("kilogram")).toBe(0.45359237)
|
|
135
|
+
expect(MetricUnit.new(1, "pound"):In("ounce")).toBeCloseTo(16, 9)
|
|
136
|
+
expect(MetricUnit.new(1, "stone"):In("pound")).toBeCloseTo(14, 9)
|
|
137
|
+
expect(MetricUnit.new(1, "acre"):In("squareFoot")).toBeCloseTo(43560, 6)
|
|
138
|
+
expect(MetricUnit.new(1, "usGallon"):In("usFluidOunce")).toBeCloseTo(128, 9)
|
|
139
|
+
expect(MetricUnit.new(1, "imperialGallon"):In("liter")).toBeCloseTo(4.54609, 9)
|
|
140
|
+
expect(MetricUnit.new(60, "milePerHour"):In("kilometerPerHour")).toBeCloseTo(96.56064, 9)
|
|
141
|
+
expect(MetricUnit.new(1, "knot"):In("kilometerPerHour")).toBeCloseTo(1.852, 9)
|
|
142
|
+
expect(MetricUnit.new(1, "poundForce"):In("newton")).toBeCloseTo(4.4482216152605, 12)
|
|
143
|
+
expect(MetricUnit.new(1, "poundForcePerSquareInch"):In("pascal")).toBeCloseTo(6894.757293168, 6)
|
|
144
|
+
expect(
|
|
145
|
+
(MetricUnit.new(1, "poundForce") / MetricUnit.pow(MetricUnit.new(1, "inch"), 2)):In(
|
|
146
|
+
"poundForcePerSquareInch"
|
|
147
|
+
)
|
|
148
|
+
).toBeCloseTo(1, 12)
|
|
149
|
+
end)
|
|
150
|
+
|
|
151
|
+
it("shows a value made in a customary unit in customary units, until converted", function()
|
|
152
|
+
expect(format(MetricUnit.new(1, "mile"))).toBe("1 mi")
|
|
153
|
+
expect(format(MetricUnit.new(1, "mile"):ToMetric())).toBe("1.609 km")
|
|
154
|
+
expect(format(MetricUnit.kilometers(1.609))).toBe("1.609 km")
|
|
155
|
+
expect(format(MetricUnit.new(1, "mile"), { unit = "mile" })).toBe("1 mi")
|
|
156
|
+
expect(format(MetricUnit.new(2, "foot"), { unit = "foot", unitDisplay = "long" })).toBe("2 feet")
|
|
157
|
+
expect(format(MetricUnit.new(1, "foot"), { unit = "foot", unitDisplay = "long" })).toBe("1 foot")
|
|
158
|
+
end)
|
|
159
|
+
|
|
160
|
+
it("picks customary units for a value that prefers them", function()
|
|
161
|
+
local function usCustomary(value: MetricUnit.MetricUnit): string
|
|
162
|
+
return format(value:ToUSCustomary())
|
|
163
|
+
end
|
|
164
|
+
expect(usCustomary(MetricUnit.kilometers(5))).toBe("3.107 mi")
|
|
165
|
+
expect(usCustomary(MetricUnit.meters(1))).toBe("3.281 ft")
|
|
166
|
+
expect(usCustomary(MetricUnit.new(10, "centimeter"))).toBe("3.937 in")
|
|
167
|
+
expect(usCustomary(MetricUnit.kilograms(1))).toBe("2.205 lb")
|
|
168
|
+
expect(usCustomary(MetricUnit.new(100, "kilometerPerHour"))).toBe("62.137 mph")
|
|
169
|
+
expect(usCustomary(MetricUnit.celsius(100))).toBe("212 °F")
|
|
170
|
+
expect(usCustomary(MetricUnit.difference(5, "celsius"))).toBe("9 °F")
|
|
171
|
+
expect(usCustomary(MetricUnit.new(1, "bar"))).toBe("14.504 psi")
|
|
172
|
+
expect(usCustomary(MetricUnit.new(1500, "joule"))).toBe("1.422 Btu")
|
|
173
|
+
-- Dimensions without US customary display units stay metric
|
|
174
|
+
expect(usCustomary(MetricUnit.new(5, "volt"))).toBe("5 V")
|
|
175
|
+
expect(format(MetricUnit.kilometers(5):ToUSCustomary(), { autoUnit = false })).toBe("5,000 m")
|
|
176
|
+
end)
|
|
177
|
+
end)
|
|
178
|
+
|
|
179
|
+
describe("MetricUnit bits", function()
|
|
180
|
+
it("shares the memory dimension with bytes, eight to a byte", function()
|
|
181
|
+
expect(MetricUnit.new(8, "bit") == MetricUnit.bytes(1)).toBe(true)
|
|
182
|
+
expect(MetricUnit.new(8, "megabit"):In("kilobyte")).toBeCloseTo(1000, 9)
|
|
183
|
+
expect(MetricUnit.new(8, "megabitPerSecond"):In("kilobytePerSecond")).toBeCloseTo(1000, 9)
|
|
184
|
+
expect(MetricUnit.new(1, "gigabitPerSecond"):GetKind()).toBe("dataRate")
|
|
185
|
+
end)
|
|
186
|
+
|
|
187
|
+
it("never switches between bits and bytes on its own", function()
|
|
188
|
+
expect(format(MetricUnit.new(8, "bit"))).toBe("1 B")
|
|
189
|
+
expect(format(MetricUnit.new(8, "kilobit"), { unit = "kilobit" })).toBe("8 kbit")
|
|
190
|
+
expect(format(MetricUnit.new(100, "megabitPerSecond"), { unit = "megabitPerSecond" })).toBe("100 Mbit/s")
|
|
191
|
+
end)
|
|
192
|
+
end)
|
|
193
|
+
|
|
194
|
+
describe("MetricUnit percentages", function()
|
|
195
|
+
it("reads and makes dimensionless proportions", function()
|
|
196
|
+
expect(MetricUnit.percent(45):In("percent")).toBeCloseTo(45, 9)
|
|
197
|
+
expect(MetricUnit.percent(45):GetBaseAmount()).toBeCloseTo(0.45, 12)
|
|
198
|
+
expect(MetricUnit.new(5, "permille"):In("percent")).toBeCloseTo(0.5, 12)
|
|
199
|
+
expect((MetricUnit.percent(45) * MetricUnit.meters(10)):In("meter")).toBeCloseTo(4.5, 9)
|
|
200
|
+
end)
|
|
201
|
+
|
|
202
|
+
it("formats a proportion as a percent only on request", function()
|
|
203
|
+
local used = MetricUnit.kilobytes(450) / MetricUnit.megabytes(1)
|
|
204
|
+
expect(format(used)).toBe("0.45")
|
|
205
|
+
expect(format(used, { unit = "percent" })).toBe("45%")
|
|
206
|
+
expect(format(used, { unit = "percent", unitDisplay = "long" })).toBe("45 percent")
|
|
207
|
+
expect(format(MetricUnit.new(5, "permille"), { unit = "permille" })).toBe("5‰")
|
|
208
|
+
expect(format(MetricUnit.percent(45):As("percent"))).toBe("45%")
|
|
209
|
+
end)
|
|
210
|
+
end)
|