diff options
Diffstat (limited to 'numpy/f2py/tests')
-rw-r--r-- | numpy/f2py/tests/src/crackfortran/gh23533.f | 5 | ||||
-rw-r--r-- | numpy/f2py/tests/src/crackfortran/gh23598.f90 | 4 | ||||
-rw-r--r-- | numpy/f2py/tests/src/crackfortran/gh23598Warn.f90 | 11 | ||||
-rw-r--r-- | numpy/f2py/tests/src/string/scalar_string.f90 | 2 | ||||
-rw-r--r-- | numpy/f2py/tests/test_character.py | 22 | ||||
-rw-r--r-- | numpy/f2py/tests/test_crackfortran.py | 60 | ||||
-rw-r--r-- | numpy/f2py/tests/test_f2py2e.py | 22 | ||||
-rw-r--r-- | numpy/f2py/tests/test_kind.py | 27 |
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}" |