• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 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 os
8import pathlib
9import unittest
10from unittest import mock
11
12import crossbench.path as pth
13from crossbench import plt
14from crossbench.plt import PLATFORM
15from crossbench.plt.bin import (Binary, BinaryNotFoundError, LinuxBinary,
16                                MacOsBinary, PosixBinary, WinBinary)
17from tests import test_helper
18from tests.crossbench.base import CrossbenchFakeFsTestCase
19from tests.crossbench.mock_helper import (LinuxMockPlatform, MacOsMockPlatform,
20                                          WinMockPlatform)
21
22
23class BinaryTestCase(CrossbenchFakeFsTestCase):
24
25  def setUp(self) -> None:
26    super().setUp()
27    self._all_mock_platforms = (
28        LinuxMockPlatform(),
29        MacOsMockPlatform(),
30        WinMockPlatform(),
31        # TODO: add adb testing
32    )
33    self._all_platforms = (PLATFORM,) + self._all_mock_platforms
34
35  def all_mock_platforms(self):
36    yield from self._all_mock_platforms
37
38  def all_platforms(self):
39    yield from self._all_platforms
40
41  def create_binary_path(self, path: pth.AnyPathLike) -> pth.LocalPath:
42    result = pth.LocalPath(path)
43    self.fs.create_file(result, st_size=100)
44    return result
45
46  def test_create_without_binary(self):
47    with self.assertRaises(ValueError):
48      Binary(name="test")
49    with self.assertRaises(ValueError):
50      Binary(name="test", posix="")
51
52  def test_new_windows_binary_invalid(self):
53    with self.assertRaises(ValueError):
54      WinBinary("custom")
55    with self.assertRaises(ValueError):
56      WinBinary(pth.AnyPath("custom"))
57    with self.assertRaises(ValueError):
58      WinBinary(pth.AnyPath("foo/bar/custom.py"))
59
60  def test_new_windows_binary(self):
61    binary = WinBinary("crossbench_mock_binary.exe")
62    self.assertEqual(binary.name, "crossbench_mock_binary.exe")
63    platform = WinMockPlatform()
64    path = platform.local_path("C:/Users/user-name/AppData/Local/Programs/"
65                               "crossbench/crossbench_mock_binary.exe")
66    with self.assertRaises(ValueError):
67      with platform.override_binary(binary, path):
68        self.assertEqual(binary.resolve(platform), path)
69
70    self.fs.create_file(path, st_size=100)
71    with mock.patch("shutil.which", return_value=path) as cm:
72      with platform.override_binary(binary, path):
73        self.assertEqual(binary.resolve(platform), path)
74        self.assertEqual(binary.resolve_cached(platform), path)
75    cm.assert_called_once_with(os.fspath(path))
76
77    # Still cached
78    self.assertEqual(binary.resolve_cached(platform), path)
79    with self.assertRaises(BinaryNotFoundError):
80      self.assertEqual(binary.resolve(platform), path)
81
82    binary.resolve_cached.cache_clear()
83    with self.assertRaises(BinaryNotFoundError):
84      self.assertEqual(binary.resolve(platform), path)
85    with self.assertRaises(BinaryNotFoundError):
86      self.assertEqual(binary.resolve_cached(platform), path)
87
88  def test_basic_accessor(self):
89    binary = Binary("test", default="foo/bar/test")
90    self.assertEqual(binary.name, "test")
91
92  def test_basic_accessor_multiple(self):
93    binary = Binary("test", default=("foo/bar/test1", "foo/bar/test2"))
94    self.assertEqual(binary.name, "test")
95
96  def test_unknown_binary(self):
97    binary = Binary("crossbench_mock_binary", default="crossbench_mock_binary")
98    for platform in self.all_platforms():
99      with self.assertRaises(BinaryNotFoundError):
100        binary.resolve(platform)
101
102  def test_known_binary_default(self):
103    for platform in self.all_mock_platforms():
104      with self.subTest(platform=platform):
105        default = pth.AnyPath("foo/bar/default/crossbench_mock_binary")
106        result = default
107        if platform.is_win:
108          result = pth.AnyPath("foo/bar/default/crossbench_mock_binary.exe")
109        binary = Binary("crossbench_mock_binary", default=default)
110        self.assertEqual(binary.platform_path(platform), (pth.AnyPath(result),))
111        with self.assertRaises(BinaryNotFoundError):
112          binary.resolve(platform)
113        with self.assertRaises(BinaryNotFoundError):
114          binary.resolve_cached(platform)
115        self.fs.create_file(result, st_size=100)
116        self.assertEqual(pth.AnyPath(binary.resolve(platform)), result)
117        self.assertEqual(pth.AnyPath(binary.resolve_cached(platform)), result)
118        self.fs.remove(result)
119
120  def test_known_binary_default_multiple(self):
121    for platform in self.all_mock_platforms():
122      with self.subTest(platform=platform):
123        default_miss = pth.AnyPath("foo/bar/default/fake")
124        default = pth.AnyPath("foo/bar/default/crossbench_mock_binary")
125        result = default
126        if platform.is_win:
127          default_miss = pth.AnyPath("foo/bar/default/fake.exe")
128          result = pth.AnyPath("foo/bar/default/crossbench_mock_binary.exe")
129        binary = Binary(
130            "crossbench_mock_binary", default=(default_miss, default))
131        self.assertEqual(
132            binary.platform_path(platform), (
133                pth.AnyPath(default_miss),
134                pth.AnyPath(result),
135            ))
136        with self.assertRaises(BinaryNotFoundError):
137          binary.resolve(platform)
138        with self.assertRaises(BinaryNotFoundError):
139          binary.resolve_cached(platform)
140        self.fs.create_file(result, st_size=100)
141        self.assertEqual(pth.AnyPath(binary.resolve(platform)), result)
142        self.assertEqual(pth.AnyPath(binary.resolve_cached(platform)), result)
143        self.fs.remove(result)
144
145  @unittest.skipUnless(plt.PLATFORM.is_posix, "Only supported on posix")
146  def test_known_binary_linux(self):
147    result = self.create_binary_path(
148        pth.AnyPosixPath("foo/bar/default/crossbench_mock_binary"))
149    binary = Binary("crossbench_mock_binary", linux=result)
150    self.validate_known_binary_linux(result, binary)
151    binary = LinuxBinary(result)
152    self.validate_known_binary_linux(result, binary)
153
154  def validate_known_binary_linux(self, result, binary):
155    result = pth.AnyPosixPath(result)
156    platform = LinuxMockPlatform()
157    self.assertEqual(str(binary.resolve(platform)), str(result))
158    self.assertEqual(str(binary.resolve_cached(platform)), str(result))
159
160    for platform in self.all_mock_platforms():
161      if platform.is_linux:
162        continue
163      self.assertEqual(binary.platform_path(platform), ())
164      with self.assertRaises(BinaryNotFoundError):
165        binary.resolve(platform)
166      with self.assertRaises(BinaryNotFoundError):
167        binary.resolve_cached(platform)
168
169  @unittest.skipUnless(plt.PLATFORM.is_posix, "Only supported on posix")
170  def test_known_binary_macos(self):
171    result = self.create_binary_path("foo/bar/default/crossbench_mock_binary")
172    binary = Binary("crossbench_mock_binary", macos=result)
173    self.validate_known_binary_macos(result, binary)
174    binary = MacOsBinary(result)
175    self.validate_known_binary_macos(result, binary)
176
177  def validate_known_binary_macos(self, result, binary):
178    platform = MacOsMockPlatform()
179    self.assertEqual(binary.resolve(platform), result)
180    self.assertEqual(binary.resolve_cached(platform), result)
181
182    for platform in self.all_mock_platforms():
183      if platform.is_macos:
184        continue
185      self.assertEqual(binary.platform_path(platform), ())
186      with self.assertRaises(BinaryNotFoundError):
187        binary.resolve(platform)
188      with self.assertRaises(BinaryNotFoundError):
189        binary.resolve_cached(platform)
190
191  @unittest.skipUnless(plt.PLATFORM.is_posix, "Only supported on posix")
192  def test_known_binary_posix(self):
193    result = self.create_binary_path("foo/bar/default/crossbench_mock_binary")
194    binary = Binary("crossbench_mock_binary", posix=result)
195    self.validate_known_binary_posix(result, binary)
196    binary = PosixBinary(result)
197    self.validate_known_binary_posix(result, binary)
198
199  def validate_known_binary_posix(self, result, binary):
200    for platform in self.all_mock_platforms():
201      if not platform.is_posix:
202        continue
203      self.assertEqual(binary.resolve(platform), result)
204      self.assertEqual(binary.resolve_cached(platform), result)
205
206    for platform in self.all_mock_platforms():
207      if platform.is_posix:
208        continue
209      self.assertEqual(binary.platform_path(platform), ())
210      with self.assertRaises(BinaryNotFoundError):
211        binary.resolve(platform)
212      with self.assertRaises(BinaryNotFoundError):
213        binary.resolve_cached(platform)
214
215  def test_known_binary_win(self):
216    result = self.create_binary_path(
217        "foo/bar/default/crossbench_mock_binary.exe")
218    result = pathlib.PureWindowsPath(result)
219    binary = Binary("crossbench_mock_binary", win=result)
220    self.validate_known_binary_win(result, binary)
221    binary = WinBinary(result)
222    self.validate_known_binary_win(result, binary)
223
224  def validate_known_binary_win(self, result, binary):
225    platform = WinMockPlatform()
226    self.assertEqual(binary.resolve(platform), result)
227    self.assertEqual(binary.resolve_cached(platform), result)
228
229    for platform in self.all_mock_platforms():
230      if platform.is_win:
231        continue
232      self.assertEqual(binary.platform_path(platform), ())
233      with self.assertRaises(BinaryNotFoundError):
234        binary.resolve(platform)
235      with self.assertRaises(BinaryNotFoundError):
236        binary.resolve_cached(platform)
237
238
239if __name__ == "__main__":
240  test_helper.run_pytest(__file__)
241