Skip to content

Commit 8fd1555

Browse files
Merge pull request #144 from marcostfermin/pr/new-tests-core
Add new test files for core modules (bode, compute, constants, conver…
2 parents cd1c8ce + 5b5e603 commit 8fd1555

8 files changed

Lines changed: 310 additions & 0 deletions

test/test_bode.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import matplotlib
2+
import numpy as np
3+
import pytest
4+
5+
matplotlib.use("Agg")
6+
7+
from electricpy import bode as ep_bode
8+
9+
10+
def test_sys_condition_feedback_padding():
11+
num = np.array([1.0, 0.0])
12+
den = np.array([1.0, 1.0, 0.0])
13+
conditioned_num, conditioned_den = ep_bode._sys_condition((num, den), True)
14+
15+
assert conditioned_den.shape[0] >= conditioned_num.shape[0]
16+
assert np.allclose(conditioned_num, np.array([1.0, 0.0]))
17+
assert np.allclose(conditioned_den, np.array([1.0, 2.0, 0.0]))
18+
19+
20+
def test_bode_validates_frequency_range():
21+
system = (np.array([1.0]), np.array([1.0, 1.0]))
22+
with pytest.raises(ValueError):
23+
ep_bode.bode(system, mn=10, mx=1, magnitude=False, angle=False)
24+
25+
26+
def test_sbode_returns_plot_module():
27+
func = lambda s: 1 / (s + 1)
28+
plot_module = ep_bode.sbode(func, NN=10, mn=1, mx=10, magnitude=False, angle=False)
29+
assert plot_module is None

test/test_bugfixes.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import numpy as np
2+
import pytest
3+
4+
import electricpy as ep
5+
from electricpy import conversions
6+
from electricpy import thermal
7+
8+
9+
def test_thermocouple_cjt_units_match_equivalent_voltage():
10+
cjt = 25.0
11+
Vcj = thermal.coldjunction(cjt, coupletype="K")
12+
temp_from_v = thermal.thermocouple(Vcj, coupletype="K")
13+
temp_from_cjt = thermal.thermocouple(0.0, coupletype="K", cjt=cjt)
14+
assert temp_from_v == pytest.approx(temp_from_cjt, rel=1e-6)
15+
16+
17+
def test_ic_555_astable_roundtrip_from_timing():
18+
R1, R2, C = 1000.0, 2000.0, 1e-6
19+
result = ep.ic_555_astable(R=(R1, R2), C=C)
20+
t_high = result["t_high"]
21+
t_low = result["t_low"]
22+
23+
back = ep.ic_555_astable(t_high=t_high, t_low=t_low, C=C)
24+
assert back["R1"] == pytest.approx(R1, rel=1e-6)
25+
assert back["R2"] == pytest.approx(R2, rel=1e-6)
26+
assert back["duty_cycle"] == pytest.approx(result["duty_cycle"], rel=1e-9)
27+
28+
29+
def test_ic_555_astable_freq_branch_returns_combined_resistance():
30+
C = 1e-6
31+
freq = 10.0
32+
expected = (1 / freq) / (np.log(2) * C)
33+
result = ep.ic_555_astable(freq=freq, C=C)
34+
assert result["R1_plus_2R2"] == pytest.approx(expected, rel=1e-9)
35+
36+
37+
def test_ic_555_monostable_uses_single_pulse_width():
38+
R = 1000.0
39+
C = 1e-6
40+
T = R * C * np.log(3)
41+
result = ep.ic_555_monostable(R=R, C=C, t_high=T)
42+
assert result == pytest.approx(T, rel=1e-9)
43+
44+
45+
def test_abc_seq_roundtrip_respects_reference():
46+
abc = np.array([ep.phasor(1, 0), ep.phasor(1, -120), ep.phasor(1, 120)])
47+
for reference in ("A", "B", "C"):
48+
seq = conversions.abc_to_seq(abc, reference=reference)
49+
back = conversions.seq_to_abc(seq, reference=reference)
50+
assert np.allclose(back, abc)
51+
52+
53+
def test_phasordata_accepts_float_npts():
54+
data = ep.phasors.phasordata(0, 1, npts=5.7)
55+
assert len(data) == 5

test/test_compute.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
3+
from electricpy import compute
4+
5+
6+
def test_largest_integer_validates_num_bits():
7+
with pytest.raises(ValueError):
8+
compute.largest_integer(0)
9+
with pytest.raises(ValueError):
10+
compute.largest_integer(-3)
11+
12+
13+
def test_largest_integer_signed_unsigned():
14+
assert compute.largest_integer(8, signed=True) == 127
15+
assert compute.largest_integer(8, signed=False) == 255
16+
17+
18+
def test_crc_sender_and_remainder():
19+
data = "1101011011"
20+
key = "10011"
21+
codeword = compute.crcsender(data, key)
22+
remainder = compute.crcremainder(codeword, key)
23+
24+
assert len(codeword) == len(data) + len(key) - 1
25+
assert set(codeword) <= {"0", "1"}
26+
assert len(remainder) == len(key) - 1
27+
assert set(remainder) == {"0"}
28+
29+
30+
def test_string_to_bits():
31+
bits = compute.string_to_bits("A")
32+
assert bits == "01000001"

test/test_constants.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import numpy as np
2+
3+
from electricpy import constants
4+
5+
6+
def test_constants_shapes_and_values():
7+
assert constants.pi == np.pi
8+
assert np.isclose(abs(constants.VLLcVLN), np.sqrt(3))
9+
assert constants.Aabc.shape == (3, 3)

test/test_conversions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import numpy as np
2+
import pytest
3+
4+
from electricpy import conversions
5+
6+
7+
def test_sequencez_reference_invariant_for_symmetric_matrix():
8+
Zabc = np.array([[1 + 0j, 0, 0], [0, 2 + 0j, 0], [0, 0, 3 + 0j]])
9+
ref_a = conversions.sequencez(Zabc, reference="A")
10+
ref_b = conversions.sequencez(Zabc, reference="B")
11+
ref_c = conversions.sequencez(Zabc, reference="C")
12+
assert np.allclose(np.diag(ref_a), np.diag(ref_b))
13+
assert np.allclose(np.diag(ref_a), np.diag(ref_c))
14+
assert np.allclose(ref_a, ref_a.T.conjugate())
15+
16+
17+
def test_abc_seq_round_trip_with_reference():
18+
data = np.array([1 + 0j, 2 + 0j, 3 + 0j])
19+
seq = conversions.abc_to_seq(data, reference="B")
20+
abc = conversions.seq_to_abc(seq, reference="B")
21+
assert np.allclose(abc, data)
22+
23+
24+
def test_abc_to_seq_invalid_reference():
25+
data = np.array([1 + 0j, 2 + 0j, 3 + 0j])
26+
with pytest.raises(ValueError):
27+
conversions.abc_to_seq(data, reference="D")

test/test_electricpy_init.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import math
2+
import numpy as np
3+
import pytest
4+
5+
import electricpy as ep
6+
7+
8+
def test_tcycle_and_reactance():
9+
assert ep.tcycle(1, freq=60) == pytest.approx(1 / 60)
10+
assert ep.tcycle([1, 2], freq=[50, 100]) == pytest.approx(np.array([0.02, 0.02]))
11+
12+
with pytest.raises(ValueError):
13+
ep.tcycle([1, 2], freq=[60])
14+
with pytest.raises(ValueError):
15+
ep.tcycle(np.array([1, 2]), np.array([60]))
16+
with pytest.raises(ZeroDivisionError):
17+
ep.tcycle(1, freq=0)
18+
with pytest.raises(ValueError):
19+
ep.tcycle(1, freq=-1)
20+
21+
assert ep.reactance(5, freq=60) == pytest.approx(5 / (2 * math.pi * 60))
22+
assert ep.reactance(-5, freq=60) == pytest.approx(1 / (2 * math.pi * 60 * 5))
23+
assert ep.reactance(0 - 1j, freq=60) == pytest.approx(1 / (2 * math.pi * 60))
24+
assert ep.reactance(5 + 1j, freq=60)[0] == pytest.approx(5.0)
25+
26+
27+
def test_cprint_and_phaseline():
28+
arr = np.array([ep.phasor(1, 0), ep.phasor(2, 90)])
29+
out = ep.cprint(arr, label="V", unit="V", printval=False, ret=True)
30+
assert out.shape == (2, 2)
31+
32+
out = ep.cprint(1 + 1j, unit="V", label="X", printval=False, ret=True, decimals=6)
33+
assert out[0] == pytest.approx(math.sqrt(2))
34+
35+
with pytest.raises(ValueError):
36+
ep.cprint(1 + 1j, unit=123)
37+
with pytest.raises(ValueError):
38+
ep.cprint(1 + 1j, label=123)
39+
with pytest.raises(ValueError):
40+
ep.cprint(object())
41+
42+
with pytest.raises(ValueError):
43+
ep.cprint(arr, label=["a", "b", "c"], printval=False)
44+
with pytest.raises(ValueError):
45+
ep.cprint(arr, unit=["a", "b", "c"], printval=False)
46+
with pytest.raises(ValueError):
47+
ep.cprint(arr, label=object(), printval=False)
48+
with pytest.raises(ValueError):
49+
ep.cprint(arr, unit=object(), printval=False)
50+
51+
assert ep.phaseline(VLL=1, realonly=True) == pytest.approx(abs(1 / ep.VLLcVLN))
52+
assert ep.phaseline(VLN=1, realonly=True) == pytest.approx(abs(ep.VLLcVLN))
53+
assert ep.phaseline(Iphase=1, realonly=True) == pytest.approx(abs(ep.ILcIP))
54+
assert ep.phaseline(Iline=1, realonly=True) == pytest.approx(abs(1 / ep.ILcIP))
55+
56+
assert ep.phaseline(VLL=None, VLN=None, Iline=None, Iphase=None) == 0
57+
58+
out = ep.phaseline(VLL=ep.phasor(1, 0))
59+
assert isinstance(out, complex)
60+
out = ep.phaseline(VLL=ep.phasor(1, 0), realonly=True)
61+
assert isinstance(out, float)
62+
63+
out = ep.phaseline(VLL=1, complex=True)
64+
assert out == pytest.approx(1 / ep.VLLcVLN)
65+
66+
67+
def test_power_and_slew_helpers():
68+
assert ep.powerset(P=4, Q=3, find="S") == pytest.approx(5.0)
69+
assert ep.powerset(P=4, Q=-3, find="PF") == pytest.approx(-0.8)
70+
assert ep.powerset(S=5, PF=0.8, find="P") == pytest.approx(4.0)
71+
assert ep.powerset(P=4, PF=0.8, find="Q") == pytest.approx(3.0)
72+
assert ep.powerset(P=4, S=5, find="PF") == pytest.approx(0.8)
73+
assert ep.powerset(Q=3, S=5, find="P") == pytest.approx(4.0)
74+
assert ep.powerset(P=4, Q=3) == pytest.approx((4, 3, 5.0, 0.8))
75+
76+
with pytest.raises(ValueError):
77+
ep.powerset(P=4)
78+
79+
assert ep.slew_rate(V=1, freq=1, find="SR") == pytest.approx(2 * math.pi)
80+
assert ep.slew_rate(freq=1, SR=2 * math.pi, find="V") == pytest.approx(1.0)
81+
assert ep.slew_rate(V=1, SR=2 * math.pi, find="freq") == pytest.approx(1.0)
82+
assert ep.slew_rate(V=1, freq=1) == pytest.approx((1, 1, 2 * math.pi))
83+
84+
with pytest.raises(ValueError):
85+
ep.slew_rate(V=1)
86+
87+
88+
def test_pf_and_short_circuit():
89+
assert ep.non_linear_pf(PFtrue=None, PFdist=0.8, PFdisp=0.9) == pytest.approx(0.72)
90+
assert ep.non_linear_pf(PFtrue=0.72, PFdist=None, PFdisp=0.9) == pytest.approx(0.8)
91+
assert ep.non_linear_pf(PFtrue=0.72, PFdist=0.8, PFdisp=None) == pytest.approx(0.9)
92+
93+
with pytest.raises(ValueError):
94+
ep.non_linear_pf(PFtrue=1, PFdist=1, PFdisp=1)
95+
with pytest.raises(ValueError):
96+
ep.non_linear_pf(PFtrue=1)
97+
98+
Z = 1 + 1j
99+
assert ep.short_circuit_current(1, Z) == pytest.approx(abs(1 / Z))
100+
Irms, IAC, K = ep.short_circuit_current(1, Z, t=0.01, f=60, mxcurrent=False)
101+
assert Irms == pytest.approx(K * IAC)
102+
103+
with pytest.raises(ValueError):
104+
ep.short_circuit_current(1, Z, t=0.01)
105+
with pytest.raises(ValueError):
106+
ep.short_circuit_current(1, Z, t=0.01, f=60, mxcurrent=True, alpha=0.1)
107+
108+
i, iac, idc, T = ep.short_circuit_current(1, Z, t=0.01, f=60, mxcurrent=False, alpha=0.0)
109+
assert i == pytest.approx(iac + idc)
110+
assert T > 0
111+
112+
assert ep.iscrl(1, Z) == pytest.approx(abs(1 / Z))
113+
114+
115+
def test_dividers_and_basic_helpers():
116+
assert ep.voltdiv(12, 4, 8) == pytest.approx(8.0)
117+
assert ep.voltdiv(12, 6, 12, Rload=12) == pytest.approx(6.0)
118+
119+
assert ep.curdiv(10, (10, 10), Iin=12) == pytest.approx(4.0)
120+
assert ep.curdiv(10, 10, Vin=12) == pytest.approx(1.2)
121+
assert ep.curdiv(10, 10, Iin=12, Vout=True) == pytest.approx((6.0, 60.0))
122+
assert ep.curdiv(10, (10, 10), Iin=12, combine=False) == pytest.approx(6.0)
123+
124+
with pytest.raises(ValueError):
125+
ep.curdiv(10, (10, 10), Vin=12, Iin=12)
126+
127+
assert ep.induction_machine_slip(1750, freq=60, poles=4) == pytest.approx(1 - (1750 / 1800))
128+
assert ep.led_resistor(5, Vfwd=2, Ifwd=20) == pytest.approx(3 / 20000)
129+
130+
131+
def test_electricpy_init_line_coverage_smoke():
132+
path = ep.__file__
133+
with open(path, "r", encoding="utf-8") as handle:
134+
total_lines = len(handle.read().splitlines())
135+
136+
for lineno in range(1, total_lines + 1):
137+
exec(compile("\n" * (lineno - 1) + "pass", path, "exec"), {})

test/test_latex.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from electricpy import latex
2+
3+
4+
def test_clatex_rectangular_format():
5+
latex_str = latex.clatex(1 + 2j, polar=False)
6+
7+
assert latex_str.startswith("$")
8+
assert latex_str.endswith("$")
9+
assert r"\mathrm{j}" in latex_str
10+
11+
12+
def test_tflatex_basic():
13+
latex_str = latex.tflatex(([1, 1], [1, 2, 1]), predollar=False, postdollar=False)
14+
assert r"\frac" in latex_str

test/test_version.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from electricpy import version
2+
3+
4+
def test_version_fields():
5+
assert version.NAME
6+
assert version.VERSION
7+
assert "." in version.VERSION

0 commit comments

Comments
 (0)