• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from __future__ import annotations
6
7import datetime as dt
8import os
9import pathlib
10import sys
11import tempfile
12import unittest
13
14from crossbench import compat, plt
15from crossbench.plt.base import DEFAULT_CACHE_DIR
16from crossbench.plt.posix import PosixPlatform
17from tests import test_helper
18
19
20class NativePlatformTestCase(unittest.TestCase):
21
22  def setUp(self):
23    self.platform: plt.Platform = plt.PLATFORM
24
25  def test_sleep(self):
26    self.platform.sleep(0)
27    self.platform.sleep(0.01)
28    self.platform.sleep(dt.timedelta())
29    self.platform.sleep(dt.timedelta(seconds=0.1))
30
31  def test_cpu_details(self):
32    details = self.platform.cpu_details()
33    self.assertLess(0, details["physical cores"])
34
35  def test_get_relative_cpu_speed(self):
36    self.assertGreater(self.platform.get_relative_cpu_speed(), 0)
37
38  def test_is_thermal_throttled(self):
39    self.assertIsInstance(self.platform.is_thermal_throttled(), bool)
40
41  def test_is_battery_powered(self):
42    self.assertIsInstance(self.platform.is_battery_powered, bool)
43    self.assertEqual(
44        self.platform.is_battery_powered,
45        plt.PLATFORM.is_battery_powered,
46    )
47
48  def test_cpu_usage(self):
49    self.assertGreaterEqual(self.platform.cpu_usage(), 0)
50
51  def test_system_details(self):
52    self.assertIsNotNone(self.platform.system_details())
53
54  def test_environ(self):
55    env = self.platform.environ
56    self.assertTrue(env)
57
58  def test_which_none(self):
59    with self.assertRaises(ValueError):
60      self.platform.which("")
61
62  def test_which_invalid_binary(self):
63    with tempfile.TemporaryDirectory() as tmp_dirname:
64      self.assertIsNone(self.platform.which(tmp_dirname))
65
66  def test_search_binary_empty_path(self):
67    with self.assertRaises(ValueError) as cm:
68      self.platform.search_binary(pathlib.Path())
69    self.assertIn("empty", str(cm.exception))
70    with self.assertRaises(ValueError) as cm:
71      self.platform.search_binary(pathlib.Path(""))
72    self.assertIn("empty", str(cm.exception))
73
74  def test_search_app_empty_path(self):
75    with self.assertRaises(ValueError) as cm:
76      self.platform.search_app(pathlib.Path())
77    self.assertIn("empty", str(cm.exception))
78    with self.assertRaises(ValueError) as cm:
79      self.platform.search_app(pathlib.Path(""))
80    self.assertIn("empty", str(cm.exception))
81
82  def test_cat(self):
83    with tempfile.TemporaryDirectory() as tmp_dirname:
84      file = pathlib.Path(tmp_dirname) / "test.txt"
85      with file.open("w") as f:
86        f.write("a b c d e f 11")
87      result = self.platform.cat(file)
88      self.assertEqual(result, "a b c d e f 11")
89
90  def test_cat_bytes(self):
91    with tempfile.TemporaryDirectory() as tmp_dirname:
92      file = pathlib.Path(tmp_dirname) / "test.data"
93      with file.open("wb") as f:
94        f.write(b"a b c d e f 11")
95      result = self.platform.cat_bytes(file)
96      self.assertEqual(result, b"a b c d e f 11")
97
98  def test_mkdir(self):
99    with tempfile.TemporaryDirectory() as tmp_dirname:
100      path = pathlib.Path(tmp_dirname) / "foo" / "bar"
101      self.assertFalse(self.platform.exists(path))
102      self.platform.mkdir(path)
103      self.assertTrue(path.is_dir())
104
105  def test_rm_file(self):
106    with tempfile.TemporaryDirectory() as tmp_dirname:
107      path = pathlib.Path(tmp_dirname) / "foo.txt"
108      path.touch()
109      self.assertTrue(path.is_file())
110      self.platform.rm(path)
111      self.assertFalse(self.platform.exists(path))
112
113  def test_rm_dir(self):
114    with tempfile.TemporaryDirectory() as tmp_dirname:
115      path = pathlib.Path(tmp_dirname) / "foo" / "bar"
116      path.mkdir(parents=True, exist_ok=False)
117      self.assertTrue(path.is_dir())
118      with self.assertRaises(Exception):
119        self.platform.rm(path.parent)
120      self.platform.rm(path.parent, dir=True)
121      self.assertFalse(self.platform.exists(path))
122      self.assertFalse(path.parent.exists())
123
124  def test_mkdtemp(self):
125    result = self.platform.mkdtemp(prefix="a_custom_prefix")
126    self.assertTrue(self.platform.is_dir(result))
127    self.assertIn("a_custom_prefix", result.name)
128    self.platform.rm(result, dir=True)
129    self.assertFalse(self.platform.exists(result))
130
131  def test_mkdtemp_dir(self):
132    with tempfile.TemporaryDirectory() as tmp_dirname:
133      tmp_dir = pathlib.Path(tmp_dirname)
134      result = self.platform.mkdtemp(dir=tmp_dir)
135      self.assertTrue(self.platform.is_dir(result))
136      self.assertTrue(compat.is_relative_to(result, tmp_dir))
137    self.assertFalse(self.platform.exists(result))
138
139  def test_mktemp(self):
140    result = self.platform.mktemp(prefix="a_custom_prefix")
141    self.assertTrue(self.platform.is_file(result))
142    self.assertIn("a_custom_prefix", result.name)
143    self.platform.rm(result)
144    self.assertFalse(self.platform.exists(result))
145
146  def test_mktemp_dir(self):
147    with tempfile.TemporaryDirectory() as tmp_dirname:
148      tmp_dir = pathlib.Path(tmp_dirname)
149      result = self.platform.mktemp(dir=tmp_dir)
150      self.assertTrue(self.platform.is_file(result))
151      self.assertTrue(compat.is_relative_to(result, tmp_dir))
152    self.assertFalse(self.platform.exists(result))
153
154  def test_exists(self):
155    with tempfile.TemporaryDirectory() as tmp_dirname:
156      tmp_dir = pathlib.Path(tmp_dirname)
157      self.assertTrue(self.platform.exists(tmp_dir))
158      self.assertFalse(self.platform.exists(tmp_dir / "foo"))
159
160  def test_touch(self):
161    with tempfile.TemporaryDirectory() as tmp_dirname:
162      tmp_file = pathlib.Path(tmp_dirname) / "test.txt"
163      self.assertFalse(tmp_file.exists())
164      self.assertFalse(self.platform.exists(tmp_file))
165      self.platform.touch(tmp_file)
166      self.assertTrue(tmp_file.exists())
167      self.assertTrue(self.platform.exists(tmp_file))
168      self.assertEqual(tmp_file.stat().st_size, 0)
169
170  def test_rename(self):
171    with tempfile.TemporaryDirectory() as tmp_dirname:
172      tmp_file = pathlib.Path(tmp_dirname) / "test.txt"
173      tmp_file_renamed = tmp_file.with_name("test_renamed.txt")
174      self.platform.touch(tmp_file)
175      self.assertTrue(tmp_file.exists())
176      self.assertFalse(tmp_file_renamed.exists())
177      result = self.platform.rename(tmp_file, tmp_file_renamed)
178      self.assertEqual(result, tmp_file_renamed)
179      self.assertFalse(tmp_file.exists())
180      self.assertTrue(tmp_file_renamed.exists())
181
182  def test_default_tmp_dir(self):
183    self.assertTrue(self.platform.is_dir(self.platform.default_tmp_dir))
184
185  def test_NamedTemporaryFile(self):
186    with self.platform.NamedTemporaryFile("custom_prefix") as path:
187      self.assertIn("custom_prefix", str(path))
188      self.assertTrue(self.platform.is_file(path))
189      self.assertTrue(self.platform.exists(path))
190    self.assertFalse(self.platform.exists(path))
191
192  def test_copy(self):
193    with tempfile.TemporaryDirectory() as tmp_dirname:
194      src_file = pathlib.Path(tmp_dirname) / "src.txt"
195      dst_file = pathlib.Path(tmp_dirname) / "dst.txt"
196      with self.assertRaises(ValueError) as cm:
197        self.assertFalse(self.platform.exists(src_file))
198        self.platform.copy(src_file, dst_file)
199      self.assertIn(str(src_file), str(cm.exception))
200      self.assertFalse(self.platform.exists(src_file))
201      self.assertFalse(self.platform.exists(dst_file))
202
203      src_file.write_text("some data")
204      self.assertTrue(self.platform.exists(src_file))
205      self.platform.copy(src_file, dst_file)
206      self.assertTrue(self.platform.exists(src_file))
207      self.assertTrue(self.platform.exists(dst_file))
208      self.assertEqual(self.platform.cat(src_file), "some data")
209      self.assertEqual(self.platform.cat(dst_file), "some data")
210
211  def test_home(self):
212    self.assertEqual(self.platform.home(), pathlib.Path.home())
213
214  def test_absolute_absolute(self):
215    if self.platform.is_win:
216      absolute_path = pathlib.Path("C:/foo")
217    else:
218      absolute_path = pathlib.Path("/foo")
219    self.assertTrue(absolute_path.is_absolute())
220    self.assertEqual(self.platform.absolute(absolute_path), absolute_path)
221
222  def test_absolute_relative(self):
223    if self.platform.is_remote:
224      self.skipTest("Not supported yet on remote platforms.")
225    relative_path = pathlib.Path("../../foo")
226    self.assertFalse(relative_path.is_absolute())
227    self.assertEqual(
228        self.platform.absolute(relative_path), relative_path.absolute())
229
230  def test_glob(self):
231    if self.platform.is_remote:
232      self.skipTest("Not supported yet on remote platforms.")
233    with tempfile.TemporaryDirectory() as tmp_dirname:
234      tmp_dir = pathlib.Path(tmp_dirname)
235      self.assertFalse(list(self.platform.glob(tmp_dir, "*")))
236      a = tmp_dir / "a"
237      b = tmp_dir / "b"
238      self.platform.touch(a)
239      self.platform.touch(b)
240      self.assertListEqual(sorted(self.platform.glob(tmp_dir, "*")), [a, b])
241
242  def test_set_file_contents(self):
243    if self.platform.is_remote:
244      self.skipTest("Not supported yet on remote platforms.")
245    with tempfile.TemporaryDirectory() as tmp_dirname:
246      tmp_file = pathlib.Path(tmp_dirname) / "test.txt"
247      self.assertFalse(self.platform.exists(tmp_file))
248      self.platform.mkdir(tmp_file.parent)
249      self.platform.touch(tmp_file)
250      self.assertFalse(self.platform.cat(tmp_file))
251
252      self.platform.set_file_contents(tmp_file, "custom data")
253      self.assertTrue(self.platform.exists(tmp_file))
254      self.assertEqual(self.platform.cat(tmp_file), "custom data")
255
256  def test_set_file_contents_dir(self):
257    if self.platform.is_remote:
258      self.skipTest("Not supported yet on remote platforms.")
259    with tempfile.TemporaryDirectory() as tmp_dirname:
260      self.assertTrue(self.platform.is_dir(tmp_dirname))
261      tmp_dir_path = self.platform.path(tmp_dirname)
262      self.assertTrue(self.platform.is_dir(tmp_dir_path))
263      with self.assertRaises(Exception) as cm:
264        self.platform.set_file_contents(tmp_dirname, "data")
265      self.assertIn(tmp_dir_path.name, str(cm.exception))
266
267  def test_path_tests(self):
268    with tempfile.TemporaryDirectory() as tmp_dirname:
269      tmp_dir = pathlib.Path(tmp_dirname)
270      self.assertTrue(self.platform.exists(tmp_dir))
271      self.assertTrue(self.platform.is_dir(tmp_dir))
272      self.assertFalse(self.platform.is_file(tmp_dir))
273
274      foo_dir = tmp_dir / "foo"
275      self.assertFalse(self.platform.exists(foo_dir))
276      self.assertFalse(self.platform.is_dir(foo_dir))
277      self.assertFalse(self.platform.is_file(foo_dir))
278      self.platform.mkdir(foo_dir)
279      self.assertTrue(self.platform.exists(foo_dir))
280      self.assertTrue(self.platform.is_dir(foo_dir))
281      self.assertFalse(self.platform.is_file(foo_dir))
282
283      bar_file = tmp_dir / "bar.txt"
284      self.assertFalse(self.platform.exists(bar_file))
285      self.assertFalse(self.platform.is_dir(bar_file))
286      self.assertFalse(self.platform.is_file(bar_file))
287      self.platform.touch(bar_file)
288      self.assertTrue(self.platform.exists(bar_file))
289      self.assertFalse(self.platform.is_dir(bar_file))
290      self.assertTrue(self.platform.is_file(bar_file))
291
292  def test_cache_dir(self):
293    with self.platform.TemporaryDirectory() as tmp_dir:
294      try:
295        self.platform.set_cache_dir(tmp_dir)
296        cache_dir = self.platform.local_cache_dir("test")
297        self.assertTrue(self.platform.is_dir(cache_dir))
298        self.assertEqual(cache_dir.parent, tmp_dir)
299      finally:
300        self.platform.rm(cache_dir, dir=True, missing_ok=True)
301        if self.platform.is_local:
302          self.platform.set_cache_dir(DEFAULT_CACHE_DIR)
303
304  def test_default_local_cache_dir(self):
305    if self.platform.is_remote:
306      return
307    cache_dir = self.platform.local_cache_dir()
308    try:
309      self.assertTrue(self.platform.is_dir(cache_dir))
310      self.assertEqual(cache_dir, DEFAULT_CACHE_DIR)
311    finally:
312      self.platform.rm(cache_dir, dir=True, missing_ok=True)
313
314  def test_local_cache_dir(self):
315    if self.platform.is_remote:
316      return
317    cache_dir = self.platform.local_cache_dir("test")
318    try:
319      self.assertTrue(self.platform.is_dir(cache_dir))
320      self.assertEqual(cache_dir.parent, DEFAULT_CACHE_DIR)
321    finally:
322      self.platform.rm(cache_dir, dir=True, missing_ok=True)
323
324  def test_has_display(self):
325    self.assertIn(self.platform.has_display, (True, False))
326
327  def test_processes(self):
328    if self.platform.is_remote:
329      self.skipTest("Not supported yet on remote platforms.")
330    processes = self.platform.processes(["name"])
331    self.assertTrue(processes)
332    for process_info in processes:
333      self.assertIn("name", process_info)
334
335  def test_process_running(self):
336    if self.platform.is_remote:
337      self.skipTest("Not supported yet on remote platforms.")
338    if self.platform.is_win:
339      self.skipTest("Too Slow on windows")
340    if test_helper.is_google_env():
341      self.skipTest("Not supported yet in google environment.")
342    self.assertFalse(self.platform.process_running([]))
343    self.assertFalse(
344        self.platform.process_running(["crossbench_invalid_test_bin"]))
345    executable = pathlib.Path(sys.executable)
346    self.assertTrue(self.platform.process_running([executable.name]))
347
348  def test_process_info(self):
349    if self.platform.is_remote:
350      self.skipTest("Not supported yet on remote platforms.")
351    if test_helper.is_google_env():
352      self.skipTest("Not supported yet in google environment.")
353    process_info = self.platform.process_info(os.getpid())
354    self.assertIn("python", process_info["name"].lower())
355
356  def test_process_children(self):
357    if self.platform.is_remote:
358      self.skipTest("Not supported yet on remote platforms.")
359    process_info = self.platform.process_children(os.getpid())
360    self.assertIsInstance(process_info, list)
361    process_info = self.platform.process_children(os.getpid(), recursive=True)
362    self.assertIsInstance(process_info, list)
363
364  @unittest.skipIf(
365      not plt.PLATFORM.which("python3"), reason="python3 not installed")
366  def test_binary_lookup_override(self):
367    test_binary = "crossbench-non-existing-test-binary"
368    self.assertIsNone(self.platform.lookup_binary_override(test_binary))
369    self.assertIsNone(self.platform.which(test_binary))
370    # Use an arbitrary existing binary for testing.
371    override_binary = self.platform.which("python3")
372    self.assertTrue(override_binary)
373    with self.platform.override_binary(test_binary, override_binary):
374      self.assertEqual(self.platform.which(test_binary), override_binary)
375      with self.platform.override_binary(test_binary, None):
376        self.assertIsNone(self.platform.lookup_binary_override(test_binary))
377        self.assertIsNone(self.platform.which(test_binary))
378      self.assertEqual(self.platform.which(test_binary), override_binary)
379    self.assertIsNone(self.platform.lookup_binary_override(test_binary))
380    self.assertIsNone(self.platform.which(test_binary))
381
382
383@unittest.skipIf(not plt.PLATFORM.is_posix, "Incompatible platform")
384class PosixNativePlatformTestCase(NativePlatformTestCase):
385  platform: PosixPlatform
386
387  def setUp(self):
388    super().setUp()
389    assert isinstance(plt.PLATFORM, PosixPlatform)
390    self.platform: PosixPlatform = plt.PLATFORM
391
392  def test_sh(self):
393    ls = self.platform.sh_stdout("ls")
394    self.assertTrue(ls)
395    lsa = self.platform.sh_stdout("ls", "-a")
396    self.assertTrue(lsa)
397    self.assertNotEqual(ls, lsa)
398
399  def test_sh_bytes(self):
400    ls_bytes = self.platform.sh_stdout_bytes("ls")
401    self.assertIsInstance(ls_bytes, bytes)
402    ls_str = self.platform.sh_stdout("ls")
403    self.assertEqual(ls_str, ls_bytes.decode("utf-8"))
404
405  def test_which(self):
406    ls_bin = self.platform.which("ls")
407    self.assertIsNotNone(ls_bin)
408    bash_bin = self.platform.which("bash")
409    self.assertIsNotNone(bash_bin)
410    self.assertNotEqual(ls_bin, bash_bin)
411    self.assertTrue(pathlib.Path(ls_bin).exists())
412    self.assertTrue(pathlib.Path(bash_bin).exists())
413
414  def test_system_details(self):
415    details = self.platform.system_details()
416    self.assertTrue(details)
417
418  def test_search_binary(self):
419    result_path = self.platform.search_binary(pathlib.Path("ls"))
420    self.assertIsNotNone(result_path)
421    self.assertIn("ls", result_path.parts)
422    self.assertTrue(self.platform.exists(result_path))
423
424  def test_search_binary_posix_lookup_override(self):
425    path = pathlib.Path("ls")
426    override = self.platform.which("cp")
427    with self.platform.override_binary(path, override):
428      result_path = self.platform.search_binary(path)
429      self.assertEqual(result_path, override)
430      self.assertTrue(self.platform.exists(result_path))
431
432    result_path_2 = self.platform.search_binary(path)
433    self.assertNotEqual(result_path_2, result_path)
434    self.assertTrue(self.platform.exists(result_path_2))
435    self.assertIsNone(self.platform.lookup_binary_override(path))
436
437  def test_environ(self):
438    env = self.platform.environ
439    self.assertTrue(env)
440    self.assertIn("PATH", env)
441    self.assertTrue(list(env))
442
443  def test_environ_set_property(self):
444    env = self.platform.environ
445    custom_key = f"CROSSBENCH_TEST_KEY_{len(env)}"
446    self.assertNotIn(custom_key, env)
447    with self.assertRaises(Exception):
448      env[custom_key] = 1234
449    env[custom_key] = "1234"
450    self.assertEqual(env[custom_key], "1234")
451    self.assertIn(custom_key, env)
452    del env[custom_key]
453    self.assertNotIn(custom_key, env)
454
455  def test_app_version(self):
456    if test_helper.is_google_env():
457      self.skipTest("Not supported yet in google environment.")
458    python_path = sys.executable
459    with self.assertRaises(ValueError):
460      self.platform.app_version("path/to/invalid/test/crossbench/bin")
461    version = self.platform.app_version(python_path)
462    self.assertTrue(version)
463
464class MockRemotePosixPlatform(type(plt.PLATFORM)):
465
466  @property
467  def host_platform(self):
468    return plt.PLATFORM
469
470  def is_remote(self) -> bool:
471    return True
472
473  def local_path(self, path):
474    # override to bypass is_local checks
475    return pathlib.Path(path)
476
477  def sh(self, *args, **kwargs):
478    return plt.PLATFORM.sh(*args, **kwargs)
479
480  def sh_stdout(self, *args, **kwargs):
481    return plt.PLATFORM.sh_stdout(*args, **kwargs)
482
483
484@unittest.skipIf(not plt.PLATFORM.is_posix, "Incompatible platform")
485class MockRemotePosixPlatformTestCase(PosixNativePlatformTestCase):
486  """All Posix operations should also work on a remote platform (e.g. via SSH).
487  This test fakes this by temporarily changing the current PLATFORM's is_remote
488  getter to return True"""
489
490  def setUp(self):
491    super().setUp()
492    self.platform = MockRemotePosixPlatform()
493
494  def test_is_remote(self):
495    self.assertTrue(self.platform.is_remote)
496
497  def tests_default_tmp_dir(self):
498    self.assertEqual(self.platform.default_tmp_dir,
499                     plt.PLATFORM.default_tmp_dir)
500
501  def test_environ_set_property(self):
502    raise self.skipTest("Not supported on remote platforms")
503
504  def test_cpu_usage(self):
505    raise self.skipTest("Not supported on remote platforms")
506
507
508@unittest.skipIf(not plt.PLATFORM.is_macos, "Incompatible platform")
509class MacOSNativePlatformTestCase(PosixNativePlatformTestCase):
510  platform: plt.MacOSPlatform
511
512  def setUp(self):
513    super().setUp()
514    assert isinstance(plt.PLATFORM, plt.MacOSPlatform)
515    self.platform = plt.PLATFORM
516
517  def test_search_app_binary_not_found(self):
518    binary = self.platform.search_binary(pathlib.Path("Invalid App Name"))
519    self.assertIsNone(binary)
520    binary = self.platform.search_binary(pathlib.Path("Non-existent App.app"))
521    self.assertIsNone(binary)
522
523  def test_search_app_binary(self):
524    binary = self.platform.search_binary(pathlib.Path("Safari.app"))
525    self.assertIsNotNone(binary)
526    self.assertTrue(self.platform.is_file(binary))
527    # We should get the binary not the app bundle
528    self.assertFalse(binary.suffix, ".app")
529    self.assertEqual(binary.name, "Safari")
530
531  def test_search_app_binary_override(self):
532    override = pathlib.Path("/System/Applications/Calendar.app")
533    with self.platform.override_binary("Safari.app", override):
534      binary = self.platform.search_binary(pathlib.Path("Safari.app"))
535      self.assertIsNotNone(binary)
536      self.assertTrue(self.platform.is_file(binary))
537      # We should get the binary not the app bundle
538      self.assertFalse(binary.suffix, ".app")
539    self.assertEqual(binary.name, "Calendar")
540
541  def test_search_app_invalid(self):
542    with self.assertRaises(ValueError):
543      self.platform.search_app(pathlib.Path("Invalid App Name"))
544
545  def test_search_app_none(self):
546    self.assertIsNone(self.platform.search_app(pathlib.Path("No App.app")))
547
548  def test_search_app(self):
549    binary = self.platform.search_app(pathlib.Path("Safari.app"))
550    self.assertIsNotNone(binary)
551    self.assertTrue(self.platform.exists(binary))
552    self.assertTrue(self.platform.is_dir(binary))
553
554  def test_search_app_override(self):
555    override = pathlib.Path("/System/Applications/Calendar.app")
556    with self.platform.override_binary("Safari.app", override):
557      binary = self.platform.search_app(pathlib.Path("Safari.app"))
558      self.assertIsNotNone(binary)
559      self.assertTrue(self.platform.exists(binary))
560      self.assertTrue(self.platform.is_dir(binary))
561      self.assertEqual(binary.name, "Calendar.app")
562
563  def test_app_version_app(self):
564    app = self.platform.search_app(pathlib.Path("Safari.app"))
565    self.assertIsNotNone(app)
566    self.assertTrue(app.is_dir())
567    version = self.platform.app_version(app)
568    self.assertRegex(version, r"[0-9]+\.[0-9]+")
569
570  def test_app_version_app_binary(self):
571    binary = self.platform.search_binary(pathlib.Path("Safari.app"))
572    self.assertIsNotNone(binary)
573    self.assertTrue(binary.is_file())
574    version = self.platform.app_version(binary)
575    self.assertRegex(version, r"[0-9]+\.[0-9]+")
576
577  def test_app_version_binary(self):
578    binary = pathlib.Path("/usr/bin/safaridriver")
579    self.assertTrue(binary.is_file())
580    version = self.platform.app_version(binary)
581    self.assertRegex(version, r"[0-9]+\.[0-9]+")
582
583  def test_name(self):
584    self.assertEqual(self.platform.name, "macos")
585
586  def test_version(self):
587    self.assertTrue(self.platform.version)
588    self.assertRegex(self.platform.version, r"[0-9]+\.[0-9]")
589
590  def test_device(self):
591    self.assertTrue(self.platform.device)
592    self.assertRegex(self.platform.device, r"[a-zA-Z]+[0-9]+,[0-9]+")
593
594  def test_cpu(self):
595    self.assertTrue(self.platform.cpu)
596    self.assertRegex(self.platform.cpu, r".* [0-9]+ cores")
597
598  def test_foreground_process(self):
599    self.assertTrue(self.platform.foreground_process())
600
601  def test_is_macos(self):
602    self.assertTrue(self.platform.is_macos)
603    self.assertFalse(self.platform.is_linux)
604    self.assertFalse(self.platform.is_win)
605    self.assertFalse(self.platform.is_remote)
606
607  def test_set_main_screen_brightness(self):
608    prev_level = plt.PLATFORM.get_main_display_brightness()
609    brightness_level = 32
610    plt.PLATFORM.set_main_display_brightness(brightness_level)
611    self.assertEqual(brightness_level,
612                     plt.PLATFORM.get_main_display_brightness())
613    plt.PLATFORM.set_main_display_brightness(prev_level)
614    self.assertEqual(prev_level, plt.PLATFORM.get_main_display_brightness())
615
616  def test_check_autobrightness(self):
617    self.platform.check_autobrightness()
618
619  def test_exec_apple_script(self):
620    self.assertEqual(
621        self.platform.exec_apple_script('copy "a value" to stdout').strip(),
622        "a value")
623
624  def test_exec_apple_script_args(self):
625    result = self.platform.exec_apple_script(  # pylint: disable=assignment-from-no-return
626        "copy item 1 of argv to stdout", "a value", "b")
627    self.assertEqual(result.strip(), "a value")
628    result = self.platform.exec_apple_script(  # pylint: disable=assignment-from-no-return
629        "copy item 2 of argv to stdout", "a value", "b")
630    self.assertEqual(result.strip(), "b")
631
632  def test_exec_apple_script_invalid(self):
633    with self.assertRaises(plt.SubprocessError):
634      self.platform.exec_apple_script("something is not right 11")
635
636
637@unittest.skipIf(not plt.PLATFORM.is_win, "Incompatible platform")
638class WinNativePlatformTestCase(NativePlatformTestCase):
639  platform: plt.WinPlatform
640
641  def setUp(self):
642    super().setUp()
643    assert isinstance(plt.PLATFORM, plt.WinPlatform)
644    self.platform = plt.PLATFORM
645
646  def test_sh(self):
647    ls = self.platform.sh_stdout("ls")
648    self.assertTrue(ls)
649
650  def test_search_binary(self):
651    with self.assertRaises(ValueError):
652      self.platform.search_binary(pathlib.Path("does not exist"))
653    path = self.platform.search_binary(
654        pathlib.Path("Windows NT/Accessories/wordpad.exe"))
655    self.assertTrue(path and path.exists())
656
657  def test_app_version(self):
658    path = self.platform.search_binary(
659        pathlib.Path("Windows NT/Accessories/wordpad.exe"))
660    self.assertTrue(path and path.exists())
661    version = self.platform.app_version(path)
662    self.assertIsNotNone(version)
663
664  def test_is_macos(self):
665    self.assertFalse(self.platform.is_macos)
666    self.assertFalse(self.platform.is_linux)
667    self.assertTrue(self.platform.is_win)
668    self.assertFalse(self.platform.is_remote)
669
670  def test_has_display(self):
671    self.assertIn(self.platform.has_display, (True, False))
672
673  def test_version(self):
674    self.assertTrue(self.platform.version)
675
676
677if __name__ == "__main__":
678  test_helper.run_pytest(__file__)
679