1# Copyright 2020 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Tests the functionality of the utils module's functions"""
15
16import os
17import tempfile
18import unittest
19from unittest import mock
20
21import utils
22import helper
23
24EXAMPLE_PROJECT = 'example'
25
26TEST_OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
27                            'cifuzz', 'test_data', 'out')
28
29
30class IsFuzzTargetLocalTest(unittest.TestCase):
31  """Tests the is_fuzz_target_local function."""
32
33  def test_invalid_filepath(self):
34    """Tests the function with an invalid file path."""
35    is_local = utils.is_fuzz_target_local('not/a/real/file')
36    self.assertFalse(is_local)
37    is_local = utils.is_fuzz_target_local('')
38    self.assertFalse(is_local)
39    is_local = utils.is_fuzz_target_local(' ')
40    self.assertFalse(is_local)
41
42  def test_valid_filepath(self):
43    """Checks is_fuzz_target_local function with a valid filepath."""
44
45    is_local = utils.is_fuzz_target_local(
46        os.path.join(TEST_OUT_DIR, 'example_crash_fuzzer'))
47    self.assertTrue(is_local)
48    is_local = utils.is_fuzz_target_local(TEST_OUT_DIR)
49    self.assertFalse(is_local)
50
51
52class GetFuzzTargetsTest(unittest.TestCase):
53  """Tests the get_fuzz_targets function."""
54
55  def test_valid_filepath(self):
56    """Tests that fuzz targets can be retrieved once the fuzzers are built."""
57    fuzz_targets = utils.get_fuzz_targets(TEST_OUT_DIR)
58    crash_fuzzer_path = os.path.join(TEST_OUT_DIR, 'example_crash_fuzzer')
59    nocrash_fuzzer_path = os.path.join(TEST_OUT_DIR, 'example_nocrash_fuzzer')
60    self.assertCountEqual(fuzz_targets,
61                          [crash_fuzzer_path, nocrash_fuzzer_path])
62
63    # Testing on a arbitrary directory with no fuzz targets in it.
64    fuzz_targets = utils.get_fuzz_targets(
65        os.path.join(helper.OSS_FUZZ_DIR, 'infra', 'travis'))
66    self.assertFalse(fuzz_targets)
67
68  def test_invalid_filepath(self):
69    """Tests what get_fuzz_targets return when invalid filepath is used."""
70    fuzz_targets = utils.get_fuzz_targets('not/a/valid/file/path')
71    self.assertFalse(fuzz_targets)
72
73
74class ExecuteTest(unittest.TestCase):
75  """Tests the execute function."""
76
77  def test_valid_command(self):
78    """Tests that execute can produce valid output."""
79    with tempfile.TemporaryDirectory() as tmp_dir:
80      out, err, err_code = utils.execute(['ls', '.'],
81                                         location=tmp_dir,
82                                         check_result=False)
83      self.assertEqual(err_code, 0)
84      self.assertEqual(err, '')
85      self.assertEqual(out, '')
86      out, err, err_code = utils.execute(['mkdir', 'tmp'],
87                                         location=tmp_dir,
88                                         check_result=False)
89      self.assertEqual(err_code, 0)
90      self.assertEqual(err, '')
91      self.assertEqual(out, '')
92      out, err, err_code = utils.execute(['ls', '.'],
93                                         location=tmp_dir,
94                                         check_result=False)
95      self.assertEqual(err_code, 0)
96      self.assertEqual(err, '')
97      self.assertEqual(out, 'tmp\n')
98
99  def test_error_command(self):
100    """Tests that execute can correctly surface errors."""
101    with tempfile.TemporaryDirectory() as tmp_dir:
102      out, err, err_code = utils.execute(['ls', 'notarealdir'],
103                                         location=tmp_dir,
104                                         check_result=False)
105      self.assertEqual(err_code, 2)
106      self.assertIsNotNone(err)
107      self.assertEqual(out, '')
108      with self.assertRaises(RuntimeError):
109        out, err, err_code = utils.execute(['ls', 'notarealdir'],
110                                           location=tmp_dir,
111                                           check_result=True)
112
113
114class BinaryPrintTest(unittest.TestCase):
115  """Tests for utils.binary_print."""
116
117  @unittest.skip('Causes spurious failures because of side-effects.')
118  def test_string(self):  # pylint: disable=no-self-use
119    """Tests that utils.binary_print can print a regular string."""
120    # Should execute without raising any exceptions.
121    with mock.patch('sys.stdout.buffer.write') as mocked_write:
122      utils.binary_print('hello')
123      mocked_write.assert_called_with('hello\n')
124
125  @unittest.skip('Causes spurious failures because of side-effects.')
126  def test_binary_string(self):  # pylint: disable=no-self-use
127    """Tests that utils.binary_print can print a bianry string."""
128    # Should execute without raising any exceptions.
129    with mock.patch('sys.stdout.buffer.write') as mocked_write:
130      utils.binary_print(b'hello')
131      mocked_write.assert_called_with(b'hello\n')
132
133
134if __name__ == '__main__':
135  unittest.main()
136