summaryrefslogtreecommitdiff
path: root/numpy/f2py/tests
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/f2py/tests')
-rw-r--r--numpy/f2py/tests/src/crackfortran/gh23533.f5
-rw-r--r--numpy/f2py/tests/src/crackfortran/gh23598.f904
-rw-r--r--numpy/f2py/tests/src/crackfortran/gh23598Warn.f9011
-rw-r--r--numpy/f2py/tests/src/string/scalar_string.f902
-rw-r--r--numpy/f2py/tests/test_character.py22
-rw-r--r--numpy/f2py/tests/test_crackfortran.py60
-rw-r--r--numpy/f2py/tests/test_f2py2e.py22
-rw-r--r--numpy/f2py/tests/test_kind.py27
8 files changed, 116 insertions, 37 deletions
diff --git a/numpy/f2py/tests/src/crackfortran/gh23533.f b/numpy/f2py/tests/src/crackfortran/gh23533.f
new file mode 100644
index 000000000..db522afa7
--- /dev/null
+++ b/numpy/f2py/tests/src/crackfortran/gh23533.f
@@ -0,0 +1,5 @@
+ SUBROUTINE EXAMPLE( )
+ IF( .TRUE. ) THEN
+ CALL DO_SOMETHING()
+ END IF ! ** .TRUE. **
+ END
diff --git a/numpy/f2py/tests/src/crackfortran/gh23598.f90 b/numpy/f2py/tests/src/crackfortran/gh23598.f90
new file mode 100644
index 000000000..e0dffb5ef
--- /dev/null
+++ b/numpy/f2py/tests/src/crackfortran/gh23598.f90
@@ -0,0 +1,4 @@
+integer function intproduct(a, b) result(res)
+ integer, intent(in) :: a, b
+ res = a*b
+end function
diff --git a/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90 b/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90
new file mode 100644
index 000000000..3b44efc5e
--- /dev/null
+++ b/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90
@@ -0,0 +1,11 @@
+module test_bug
+ implicit none
+ private
+ public :: intproduct
+
+contains
+ integer function intproduct(a, b) result(res)
+ integer, intent(in) :: a, b
+ res = a*b
+ end function
+end module
diff --git a/numpy/f2py/tests/src/string/scalar_string.f90 b/numpy/f2py/tests/src/string/scalar_string.f90
index d847668bb..f8f076172 100644
--- a/numpy/f2py/tests/src/string/scalar_string.f90
+++ b/numpy/f2py/tests/src/string/scalar_string.f90
@@ -1,7 +1,9 @@
MODULE string_test
character(len=8) :: string
+ character string77 * 8
character(len=12), dimension(5,7) :: strarr
+ character strarr77(5,7) * 12
END MODULE string_test
diff --git a/numpy/f2py/tests/test_character.py b/numpy/f2py/tests/test_character.py
index 5f9805158..0bb0f4290 100644
--- a/numpy/f2py/tests/test_character.py
+++ b/numpy/f2py/tests/test_character.py
@@ -576,16 +576,18 @@ class TestStringScalarArr(util.F2PyTest):
@pytest.mark.slow
def test_char(self):
- out = self.module.string_test.string
- expected = ()
- assert out.shape == expected
- expected = '|S8'
- assert out.dtype == expected
+ for out in (self.module.string_test.string,
+ self.module.string_test.string77):
+ expected = ()
+ assert out.shape == expected
+ expected = '|S8'
+ assert out.dtype == expected
@pytest.mark.slow
def test_char_arr(self):
- out = self.module.string_test.strarr
- expected = (5,7)
- assert out.shape == expected
- expected = '|S12'
- assert out.dtype == expected
+ for out in (self.module.string_test.strarr,
+ self.module.string_test.strarr77):
+ expected = (5,7)
+ assert out.shape == expected
+ expected = '|S12'
+ assert out.dtype == expected
diff --git a/numpy/f2py/tests/test_crackfortran.py b/numpy/f2py/tests/test_crackfortran.py
index 23965087d..49bfc13af 100644
--- a/numpy/f2py/tests/test_crackfortran.py
+++ b/numpy/f2py/tests/test_crackfortran.py
@@ -135,6 +135,7 @@ class TestMarkinnerspaces:
assert markinnerspaces("a 'b c' 'd e'") == "a 'b@_@c' 'd@_@e'"
assert markinnerspaces(r'a "b c" "d e"') == r'a "b@_@c" "d@_@e"'
+
class TestDimSpec(util.F2PyTest):
"""This test suite tests various expressions that are used as dimension
specifications.
@@ -244,6 +245,7 @@ class TestModuleDeclaration:
assert len(mod) == 1
assert mod[0]["vars"]["abar"]["="] == "bar('abar')"
+
class TestEval(util.F2PyTest):
def test_eval_scalar(self):
eval_scalar = crackfortran._eval_scalar
@@ -268,6 +270,7 @@ class TestFortranReader(util.F2PyTest):
mod = crackfortran.crackfortran([str(f_path)])
assert mod[0]['name'] == 'foo'
+
class TestUnicodeComment(util.F2PyTest):
sources = [util.getpath("tests", "src", "crackfortran", "unicode_comment.f90")]
@@ -278,6 +281,7 @@ class TestUnicodeComment(util.F2PyTest):
def test_encoding_comment(self):
self.module.foo(3)
+
class TestNameArgsPatternBacktracking:
@pytest.mark.parametrize(
['adversary'],
@@ -290,36 +294,44 @@ class TestNameArgsPatternBacktracking:
def test_nameargspattern_backtracking(self, adversary):
'''address ReDOS vulnerability:
https://github.com/numpy/numpy/issues/23338'''
- last_median = 0.
- trials_per_count = 128
+ trials_per_batch = 12
+ batches_per_regex = 4
start_reps, end_reps = 15, 25
- times_median_doubled = 0
for ii in range(start_reps, end_reps):
repeated_adversary = adversary * ii
- times = []
- for _ in range(trials_per_count):
- t0 = time.perf_counter()
- mtch = nameargspattern.search(repeated_adversary)
- times.append(time.perf_counter() - t0)
- # We should use a measure of time that's resilient to outliers.
- # Times jump around a lot due to the CPU's scheduler.
- median = np.median(times)
+ # test times in small batches.
+ # this gives us more chances to catch a bad regex
+ # while still catching it before too long if it is bad
+ for _ in range(batches_per_regex):
+ times = []
+ for _ in range(trials_per_batch):
+ t0 = time.perf_counter()
+ mtch = nameargspattern.search(repeated_adversary)
+ times.append(time.perf_counter() - t0)
+ # our pattern should be much faster than 0.2s per search
+ # it's unlikely that a bad regex will pass even on fast CPUs
+ assert np.median(times) < 0.2
assert not mtch
# if the adversary is capped with @)@, it becomes acceptable
# according to the old version of the regex.
# that should still be true.
good_version_of_adversary = repeated_adversary + '@)@'
assert nameargspattern.search(good_version_of_adversary)
- if ii > start_reps:
- # the hallmark of exponentially catastrophic backtracking
- # is that runtime doubles for every added instance of
- # the problematic pattern.
- times_median_doubled += median > 2 * last_median
- # also try to rule out non-exponential but still bad cases
- # arbitrarily, we should set a hard limit of 10ms as too slow
- assert median < trials_per_count * 0.01
- last_median = median
- # we accept that maybe the median might double once, due to
- # the CPU scheduler acting weird or whatever. More than that
- # seems suspicious.
- assert times_median_doubled < 2 \ No newline at end of file
+
+
+class TestFunctionReturn(util.F2PyTest):
+ sources = [util.getpath("tests", "src", "crackfortran", "gh23598.f90")]
+
+ def test_function_rettype(self):
+ # gh-23598
+ assert self.module.intproduct(3, 4) == 12
+
+
+class TestFortranGroupCounters(util.F2PyTest):
+ def test_end_if_comment(self):
+ # gh-23533
+ fpath = util.getpath("tests", "src", "crackfortran", "gh23533.f")
+ try:
+ crackfortran.crackfortran([str(fpath)])
+ except Exception as exc:
+ assert False, f"'crackfortran.crackfortran' raised an exception {exc}"
diff --git a/numpy/f2py/tests/test_f2py2e.py b/numpy/f2py/tests/test_f2py2e.py
index 2c10f046f..5f7b56a68 100644
--- a/numpy/f2py/tests/test_f2py2e.py
+++ b/numpy/f2py/tests/test_f2py2e.py
@@ -63,6 +63,15 @@ def hello_world_f90(tmpdir_factory):
@pytest.fixture(scope="session")
+def gh23598_warn(tmpdir_factory):
+ """F90 file for testing warnings in gh23598"""
+ fdat = util.getpath("tests", "src", "crackfortran", "gh23598Warn.f90").read_text()
+ fn = tmpdir_factory.getbasetemp() / "gh23598Warn.f90"
+ fn.write_text(fdat, encoding="ascii")
+ return fn
+
+
+@pytest.fixture(scope="session")
def hello_world_f77(tmpdir_factory):
"""Generates a single f77 file for testing"""
fdat = util.getpath("tests", "src", "cli", "hi77.f").read_text()
@@ -91,6 +100,19 @@ def f2cmap_f90(tmpdir_factory):
return fn
+def test_gh23598_warn(capfd, gh23598_warn, monkeypatch):
+ foutl = get_io_paths(gh23598_warn, mname="test")
+ ipath = foutl.f90inp
+ monkeypatch.setattr(
+ sys, "argv",
+ f'f2py {ipath} -m test'.split())
+
+ with util.switchdir(ipath.parent):
+ f2pycli() # Generate files
+ wrapper = foutl.wrap90.read_text()
+ assert "intproductf2pywrap, intpr" not in wrapper
+
+
def test_gen_pyf(capfd, hello_world_f90, monkeypatch):
"""Ensures that a signature file is generated via the CLI
CLI :: -h
diff --git a/numpy/f2py/tests/test_kind.py b/numpy/f2py/tests/test_kind.py
index f0cb61fb6..69b85aaad 100644
--- a/numpy/f2py/tests/test_kind.py
+++ b/numpy/f2py/tests/test_kind.py
@@ -1,5 +1,6 @@
import os
import pytest
+import platform
from numpy.f2py.crackfortran import (
_selected_int_kind_func as selected_int_kind,
@@ -11,8 +12,8 @@ from . import util
class TestKind(util.F2PyTest):
sources = [util.getpath("tests", "src", "kind", "foo.f90")]
- def test_all(self):
- selectedrealkind = self.module.selectedrealkind
+ def test_int(self):
+ """Test `int` kind_func for integers up to 10**40."""
selectedintkind = self.module.selectedintkind
for i in range(40):
@@ -20,7 +21,27 @@ class TestKind(util.F2PyTest):
i
), f"selectedintkind({i}): expected {selected_int_kind(i)!r} but got {selectedintkind(i)!r}"
- for i in range(20):
+ def test_real(self):
+ """
+ Test (processor-dependent) `real` kind_func for real numbers
+ of up to 31 digits precision (extended/quadruple).
+ """
+ selectedrealkind = self.module.selectedrealkind
+
+ for i in range(32):
+ assert selectedrealkind(i) == selected_real_kind(
+ i
+ ), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
+
+ @pytest.mark.xfail(platform.machine().lower().startswith("ppc"),
+ reason="Some PowerPC may not support full IEEE 754 precision")
+ def test_quad_precision(self):
+ """
+ Test kind_func for quadruple precision [`real(16)`] of 32+ digits .
+ """
+ selectedrealkind = self.module.selectedrealkind
+
+ for i in range(32, 40):
assert selectedrealkind(i) == selected_real_kind(
i
), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"