Repository: mesonbuild/meson

Issue:
Results of find_program('some-script") should be consistent, irrespective of value of PATHEXT
`test_find_program()` (a windows-only test) fails if `.py` isn't in `PATHEXT`

```
C:\meson>py run_unittests.py WindowsTests.test_find_program
F
Stdout:
Program cmd found: YES (C:\WINDOWS\system32\cmd.EXE)
Program cmd.exe found: YES (C:\WINDOWS\system32\cmd.exe)
Program C:\WINDOWS\system32\cmd found: YES (C:\WINDOWS\system32\cmd.exe)
Program C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script found: YES (python C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script)
Program C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script-ext.py found: YES (C:\Users\jon\AppData\Local\Programs\Python\Python36\python.exe C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script-ext.py)
Program test-script-ext found: NO

======================================================================
FAIL: test_find_program (__main__.WindowsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "run_unittests.py", line 3041, in test_find_program
    self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
AssertionError: False is not true : test-script-ext not found in PATH

Stdout:
Program cmd found: YES (C:\WINDOWS\system32\cmd.EXE)
Program cmd.exe found: YES (C:\WINDOWS\system32\cmd.exe)
Program C:\WINDOWS\system32\cmd found: YES (C:\WINDOWS\system32\cmd.exe)
Program C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script found: YES (python C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script)
Program C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script-ext.py found: YES (C:\Users\jon\AppData\Local\Programs\Python\Python36\python.exe C:\cygwin64\wip\meson\test cases/windows\8 find program\test-script-ext.py)
Program test-script-ext found: NO

----------------------------------------------------------------------
Ran 1 test in 0.059s

FAILED (failures=1)

C:\meson>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

C:\meson>set PATHEXT=%PATHEXT%;.py

C:\meson>py run_unittests.py WindowsTests.test_find_program
.
----------------------------------------------------------------------
Ran 1 test in 0.025s

OK
```



Discussion:
This test case seems a little odd.  `find_program('foo')` will (sometimes) find `foo.py` on windows, but not on any other platform?

Yes, that's how Windows `PATH` searching works. There's no executable bit, so executables are identified by their extension. The default value for `PATHEXT` is `.COM;.EXE;.BAT;.CMD` and if you want python scripts to be identified as executables, you have to append `;.PY` to that (the Python installer does this for you).

Of course this is optional, and the reason why the test contains this is just to ensure that this edge-case works (I'm sure some windows-only meson projects will want to assume that `find_program('foo')` can find `foo.py` in the correct configuration). 

Nothing in Meson depends on it, since we expect people to look for scripts with `find_program('foo.py')` since that is the cross-platform way of doing it. We can just skip that line of the test if `.PY` is not in `PATHEXT`, but we should ensure that at least one of our CI jobs has `.PY` in `PATHEXT`.
Also, Meson supports looking for scripts with a `#!.* python` named `foo` with `find_program('foo')` through manual listing of directories specified in `PATH` because a lot of Linux-origin projects tend to install scripts without extensions on all platforms (f.ex., glib).

Resolving patch:
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -4000,12 +4000,15 @@ def test_find_program(self):
         # Finding a script with an extension inside a directory works
         prog = ExternalProgram(os.path.join(testdir, 'test-script-ext.py'))
         self.assertTrue(prog.found(), msg='test-script-ext.py not found')
-        # Finding a script in PATH w/o extension works and adds the interpreter
+        # Finding a script in PATH
         os.environ['PATH'] += os.pathsep + testdir
-        prog = ExternalProgram('test-script-ext')
-        self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
-        self.assertPathEqual(prog.get_command()[0], python_command[0])
-        self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
+        # Finding a script in PATH w/o extension works and adds the interpreter
+        # (check only if `.PY` is in PATHEXT)
+        if '.PY' in [ext.upper() for ext in os.environ['PATHEXT'].split(';')]:
+            prog = ExternalProgram('test-script-ext')
+            self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
+            self.assertPathEqual(prog.get_command()[0], python_command[0])
+            self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
         # Finding a script in PATH with extension works and adds the interpreter
         prog = ExternalProgram('test-script-ext.py')
         self.assertTrue(prog.found(), msg='test-script-ext.py not found in PATH')


Test patch: