Skip to content

Commit 9eee026

Browse files
Added Energy unit and unit tests.
1 parent ffa62ae commit 9eee026

12 files changed

+1126
-0
lines changed
Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
// Copyright 2020-2025 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Globalization;
16+
using OnixLabs.Numerics;
17+
18+
namespace OnixLabs.Units.UnitTests;
19+
20+
public sealed class EnergyTests
21+
{
22+
// IEEE-754 binary floating-point arithmetic causes small discrepancies in calculation, therefore we need a tolerance.
23+
private const double Tolerance = 1e+42;
24+
25+
[Fact(DisplayName = "Energy.Zero should produce the expected result")]
26+
public void EnergyZeroShouldProduceExpectedResult()
27+
{
28+
// Given / When
29+
Energy<double> energy = Energy<double>.Zero;
30+
31+
// Then
32+
Assert.Equal(0.0, energy.YoctoJoules, Tolerance);
33+
}
34+
35+
[Theory(DisplayName = "Energy.FromYoctoJoules should produce the expected YoctoJoules")]
36+
[InlineData(0.0, 0.0)]
37+
[InlineData(1.0, 1.0)]
38+
[InlineData(2.5, 2.5)]
39+
public void EnergyFromYoctoJoulesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
40+
{
41+
// Given / When
42+
Energy<double> energy = Energy<double>.FromYoctoJoules(value);
43+
44+
// Then
45+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
46+
}
47+
48+
[Theory(DisplayName = "Energy.FromJoules should produce the expected YoctoJoules")]
49+
[InlineData(0.0, 0.0)]
50+
[InlineData(1.0, 1e24)]
51+
[InlineData(2.5, 2.5e24)]
52+
public void EnergyFromJoulesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
53+
{
54+
// Given / When
55+
Energy<double> energy = Energy<double>.FromJoules(value);
56+
57+
// Then
58+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
59+
}
60+
61+
[Theory(DisplayName = "Energy.FromKiloJoules should produce the expected YoctoJoules")]
62+
[InlineData(0.0, 0.0)]
63+
[InlineData(1.0, 1e27)]
64+
[InlineData(2.5, 2.5e27)]
65+
public void EnergyFromKiloJoulesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
66+
{
67+
// Given / When
68+
Energy<double> energy = Energy<double>.FromKiloJoules(value);
69+
70+
// Then
71+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
72+
}
73+
74+
[Theory(DisplayName = "Energy.FromMegaJoules should produce the expected YoctoJoules")]
75+
[InlineData(0.0, 0.0)]
76+
[InlineData(1.0, 1e30)]
77+
[InlineData(2.5, 2.5e30)]
78+
public void EnergyFromMegaJoulesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
79+
{
80+
// Given / When
81+
Energy<double> energy = Energy<double>.FromMegaJoules(value);
82+
83+
// Then
84+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
85+
}
86+
87+
[Theory(DisplayName = "Energy.FromGigaJoules should produce the expected YoctoJoules")]
88+
[InlineData(0.0, 0.0)]
89+
[InlineData(1.0, 1e33)]
90+
[InlineData(2.5, 2.5e33)]
91+
public void EnergyFromGigaJoulesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
92+
{
93+
// Given / When
94+
Energy<double> energy = Energy<double>.FromGigaJoules(value);
95+
96+
// Then
97+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
98+
}
99+
100+
[Theory(DisplayName = "Energy.FromCalories should produce the expected YoctoJoules")]
101+
[InlineData(0.0, 0.0)]
102+
[InlineData(1.0, 4.184e24)]
103+
[InlineData(2.5, 1.046e25)]
104+
public void EnergyFromCaloriesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
105+
{
106+
// Given / When
107+
Energy<double> energy = Energy<double>.FromCalories(value);
108+
109+
// Then
110+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
111+
}
112+
113+
[Theory(DisplayName = "Energy.FromKiloCalories should produce the expected YoctoJoules")]
114+
[InlineData(0.0, 0.0)]
115+
[InlineData(1.0, 4.184e27)]
116+
[InlineData(2.5, 1.046e28)]
117+
public void EnergyFromKiloCaloriesShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
118+
{
119+
// Given / When
120+
Energy<double> energy = Energy<double>.FromKiloCalories(value);
121+
122+
// Then
123+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
124+
}
125+
126+
[Theory(DisplayName = "Energy.FromWattHours should produce the expected YoctoJoules")]
127+
[InlineData(0.0, 0.0)]
128+
[InlineData(1.0, 3.6e27)]
129+
[InlineData(2.5, 9.0e27)]
130+
public void EnergyFromWattHoursShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
131+
{
132+
// Given / When
133+
Energy<double> energy = Energy<double>.FromWattHours(value);
134+
135+
// Then
136+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
137+
}
138+
139+
[Theory(DisplayName = "Energy.FromKiloWattHours should produce the expected YoctoJoules")]
140+
[InlineData(0.0, 0.0)]
141+
[InlineData(1.0, 3.6e30)]
142+
[InlineData(2.5, 9.0e30)]
143+
public void EnergyFromKiloWattHoursShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
144+
{
145+
// Given / When
146+
Energy<double> energy = Energy<double>.FromKiloWattHours(value);
147+
148+
// Then
149+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
150+
}
151+
152+
[Theory(DisplayName = "Energy.FromErgs should produce the expected YoctoJoules")]
153+
[InlineData(0.0, 0.0)]
154+
[InlineData(1.0, 1e17)]
155+
[InlineData(2.5, 2.5e17)]
156+
public void EnergyFromErgsShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
157+
{
158+
// Given / When
159+
Energy<double> energy = Energy<double>.FromErgs(value);
160+
161+
// Then
162+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
163+
}
164+
165+
[Theory(DisplayName = "Energy.FromBritishThermalUnits should produce the expected YoctoJoules")]
166+
[InlineData(0.0, 0.0)]
167+
[InlineData(1.0, 1.05505585262e27)]
168+
[InlineData(2.5, 2.63763963155e27)]
169+
public void EnergyFromBritishThermalUnitsShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
170+
{
171+
// Given / When
172+
Energy<double> energy = Energy<double>.FromBritishThermalUnits(value);
173+
174+
// Then
175+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
176+
}
177+
178+
[Theory(DisplayName = "Energy.FromFootPounds should produce the expected YoctoJoules")]
179+
[InlineData(0.0, 0.0)]
180+
[InlineData(1.0, 1.3558179483314e24)]
181+
[InlineData(2.5, 3.3895448708285e24)]
182+
public void EnergyFromFootPoundsShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
183+
{
184+
// Given / When
185+
Energy<double> energy = Energy<double>.FromFootPounds(value);
186+
187+
// Then
188+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
189+
}
190+
191+
[Theory(DisplayName = "Energy.FromElectronVolts should produce the expected YoctoJoules")]
192+
[InlineData(0.0, 0.0)]
193+
[InlineData(1.0, 1.602176634e5)]
194+
[InlineData(2.5, 4.005441584999999e5)]
195+
public void EnergyFromElectronVoltsShouldProduceExpectedYoctoJoules(double value, double expectedYoctoJoules)
196+
{
197+
// Given / When
198+
Energy<double> energy = Energy<double>.FromElectronVolts(value);
199+
200+
// Then
201+
Assert.Equal(expectedYoctoJoules, energy.YoctoJoules, Tolerance);
202+
}
203+
204+
[Fact(DisplayName = "Energy.Add should produce the expected result")]
205+
public void EnergyAddShouldProduceExpectedValue()
206+
{
207+
// Given
208+
Energy<double> left = Energy<double>.FromJoules(1500.0);
209+
Energy<double> right = Energy<double>.FromJoules(500.0);
210+
211+
// When
212+
Energy<double> result = left.Add(right);
213+
214+
// Then
215+
Assert.Equal(2000.0, result.Joules, Tolerance);
216+
}
217+
218+
[Fact(DisplayName = "Energy.Subtract should produce the expected result")]
219+
public void EnergySubtractShouldProduceExpectedValue()
220+
{
221+
// Given
222+
Energy<double> left = Energy<double>.FromJoules(1500.0);
223+
Energy<double> right = Energy<double>.FromJoules(400.0);
224+
225+
// When
226+
Energy<double> result = left.Subtract(right);
227+
228+
// Then
229+
Assert.Equal(1100.0, result.Joules, Tolerance);
230+
}
231+
232+
[Fact(DisplayName = "Energy.Multiply should produce the expected result")]
233+
public void EnergyMultiplyShouldProduceExpectedValue()
234+
{
235+
// Given
236+
Energy<double> left = Energy<double>.FromJoules(10.0); // 1e25 yJ
237+
Energy<double> right = Energy<double>.FromJoules(3.0); // 3e24 yJ
238+
239+
// When
240+
Energy<double> result = left.Multiply(right); // 1e25 * 3e24 = 3e49 yJ
241+
242+
// Then
243+
Assert.Equal(1e25, left.YoctoJoules, Tolerance);
244+
Assert.Equal(3e24, right.YoctoJoules, Tolerance);
245+
Assert.Equal(3e49, result.YoctoJoules, Tolerance);
246+
Assert.Equal(3e25, result.Joules, Tolerance);
247+
}
248+
249+
[Fact(DisplayName = "Energy.Divide should produce the expected result")]
250+
public void EnergyDivideShouldProduceExpectedValue()
251+
{
252+
// Given
253+
Energy<double> left = Energy<double>.FromJoules(100.0); // 1e26 yJ
254+
Energy<double> right = Energy<double>.FromJoules(20.0); // 2e25 yJ
255+
256+
// When
257+
Energy<double> result = left.Divide(right); // 1e26 / 2e25 = 5 yJ
258+
259+
// Then
260+
Assert.Equal(5.0, result.YoctoJoules, Tolerance);
261+
Assert.Equal(5e-24, result.Joules, Tolerance);
262+
}
263+
264+
[Fact(DisplayName = "Energy equality should produce the expected result (left equal to right)")]
265+
public void EnergyEqualityShouldProduceExpectedResultLeftEqualToRight()
266+
{
267+
// Given
268+
Energy<BigDecimal> left = Energy<BigDecimal>.FromKiloJoules(2.0);
269+
Energy<BigDecimal> right = Energy<BigDecimal>.FromJoules(2000.0);
270+
271+
// When / Then
272+
Assert.True(Energy<BigDecimal>.Equals(left, right));
273+
Assert.True(left.Equals(right));
274+
Assert.True(left.Equals((object)right));
275+
Assert.True(left == right);
276+
Assert.False(left != right);
277+
}
278+
279+
[Fact(DisplayName = "Energy equality should produce the expected result (left not equal to right)")]
280+
public void EnergyEqualityShouldProduceExpectedResultLeftNotEqualToRight()
281+
{
282+
// Given
283+
Energy<double> left = Energy<double>.FromKiloJoules(2.0);
284+
Energy<double> right = Energy<double>.FromJoules(2500.0);
285+
286+
// When / Then
287+
Assert.False(Energy<double>.Equals(left, right));
288+
Assert.False(left.Equals(right));
289+
Assert.False(left.Equals((object)right));
290+
Assert.False(left == right);
291+
Assert.True(left != right);
292+
}
293+
294+
[Fact(DisplayName = "Energy comparison should produce the expected result (left equal to right)")]
295+
public void EnergyComparisonShouldProduceExpectedResultLeftEqualToRight()
296+
{
297+
// Given
298+
Energy<double> left = Energy<double>.FromJoules(1234.0);
299+
Energy<double> right = Energy<double>.FromJoules(1234.0);
300+
301+
// When / Then
302+
Assert.Equal(0, Energy<double>.Compare(left, right));
303+
Assert.Equal(0, left.CompareTo(right));
304+
Assert.Equal(0, left.CompareTo((object)right));
305+
Assert.False(left > right);
306+
Assert.True(left >= right);
307+
Assert.False(left < right);
308+
Assert.True(left <= right);
309+
}
310+
311+
[Fact(DisplayName = "Energy comparison should produce the expected result (left greater than right)")]
312+
public void EnergyComparisonShouldProduceExpectedLeftGreaterThanRight()
313+
{
314+
// Given
315+
Energy<double> left = Energy<double>.FromJoules(4567.0);
316+
Energy<double> right = Energy<double>.FromJoules(1234.0);
317+
318+
// When / Then
319+
Assert.Equal(1, Energy<double>.Compare(left, right));
320+
Assert.Equal(1, left.CompareTo(right));
321+
Assert.Equal(1, left.CompareTo((object)right));
322+
Assert.True(left > right);
323+
Assert.True(left >= right);
324+
Assert.False(left < right);
325+
Assert.False(left <= right);
326+
}
327+
328+
[Fact(DisplayName = "Energy comparison should produce the expected result (left less than right)")]
329+
public void EnergyComparisonShouldProduceExpectedLeftLessThanRight()
330+
{
331+
// Given
332+
Energy<double> left = Energy<double>.FromJoules(1234.0);
333+
Energy<double> right = Energy<double>.FromJoules(4567.0);
334+
335+
// When / Then
336+
Assert.Equal(-1, Energy<double>.Compare(left, right));
337+
Assert.Equal(-1, left.CompareTo(right));
338+
Assert.Equal(-1, left.CompareTo((object)right));
339+
Assert.False(left > right);
340+
Assert.False(left >= right);
341+
Assert.True(left < right);
342+
Assert.True(left <= right);
343+
}
344+
345+
[Fact(DisplayName = "Energy.ToString should produce the expected result")]
346+
public void EnergyToStringShouldProduceExpectedResult()
347+
{
348+
// Given
349+
// Use a value that renders nicely across several specifiers.
350+
Energy<double> energy = Energy<double>.FromJoules(1000.0);
351+
352+
// When / Then
353+
Assert.Equal("1,000.000 J", $"{energy:J3}");
354+
Assert.Equal("1.000 kJ", $"{energy:kJ3}");
355+
Assert.Equal("0.001 MJ", $"{energy:MJ3}");
356+
Assert.Equal("0.000 GJ", $"{energy:GJ3}");
357+
Assert.Equal("239.006 cal", $"{energy:cal3}");
358+
Assert.Equal("0.239 kcal", $"{energy:kcal3}");
359+
Assert.Equal("0.278 Wh", $"{energy:Wh3}");
360+
Assert.Equal("0.000 kWh", $"{energy:kWh3}");
361+
Assert.Equal("10,000,000,000.000 erg", $"{energy:erg3}");
362+
Assert.Equal("0.948 BTU", $"{energy:BTU3}");
363+
Assert.Equal("737.562 ft·lbf", $"{energy:ftlb3}");
364+
Assert.Equal("6,241,509,074,460,762,701,824.000 eV", $"{energy:eV3}");
365+
}
366+
367+
[Fact(DisplayName = "Energy.ToString should honor custom culture separators")]
368+
public void EnergyToStringShouldHonorCustomCulture()
369+
{
370+
// Given
371+
CultureInfo customCulture = new("de-DE");
372+
Energy<double> energy = Energy<double>.FromJoules(1234.56);
373+
374+
// When
375+
string formatted = energy.ToString("J2", customCulture);
376+
377+
// Then
378+
// German uses '.' for thousands and ',' for decimals.
379+
Assert.Equal("1.234,56 J", formatted);
380+
}
381+
}

0 commit comments

Comments
 (0)