1"""Test suite for prance.util.fs ."""
2
3__author__ = 'Jens Finkhaeuser'
4__copyright__ = 'Copyright (c) 2016-2021 Jens Finkhaeuser'
5__license__ = 'MIT'
6__all__ = ()
7
8
9import os
10import sys
11
12import pytest
13
14from prance.util import fs
15
16from . import sandbox, platform
17
18@pytest.fixture
19def create_symlink():
20  # Defined as a fixture so we can selectively use it for tests."
21  testname = 'tests/specs/symlink_test'
22  import os, os.path
23  if os.path.islink(testname):
24    return testname
25
26  if os.path.exists(testname):
27    os.unlink(testname)
28
29  target = 'with_externals.yaml'
30  os.symlink(target, testname)
31
32  return testname
33
34
35@pytest.mark.skipif(platform('win32'), reason = 'Skip on win32')
36def test_canonical(create_symlink):
37  res = fs.canonical_filename(create_symlink)
38  expected = os.path.join(os.getcwd(), 'tests/specs/with_externals.yaml')
39  assert res == expected
40
41
42def test_to_posix_rel():
43  test = "tests/specs/with_externals.yaml"
44  assert fs.to_posix(os.path.normpath(test)) == test
45
46
47@pytest.mark.skipif(platform('win32'), reason = 'Skip on win32')
48def test_to_posix_abs_posix():
49  test = "/etc/passwd"
50  expected = test
51  assert fs.to_posix(test) == expected
52
53
54@pytest.mark.skipif(platform('!win32'), reason = 'Skip on !win32')
55def test_to_posix_abs_win32():
56  test = "c:\\windows\\notepad.exe"
57  expected = "/c:/windows/notepad.exe"
58  assert fs.to_posix(test) == expected
59
60
61def test_from_posix_rel():
62  test = "tests/specs/with_externals.yaml"
63  assert fs.from_posix(test) == os.path.normpath(test)
64
65
66@pytest.mark.skipif(platform('win32'), reason = 'Skip on win32')
67def test_from_posix_abs_posix():
68  test = "/etc/passwd"
69  expected = test
70  assert fs.from_posix(test) == expected
71
72
73@pytest.mark.skipif(platform('!win32'), reason = 'Skip on !win32')
74def test_from_posix_abs_win32():
75  test = "/c:/windows/notepad.exe"
76  expected = "c:\\windows\\notepad.exe"
77  assert fs.from_posix(test) == expected
78
79
80def test_abspath_basics():
81  testname = os.path.normpath('tests/specs/with_externals.yaml')
82  res = fs.abspath(testname)
83  expected = fs.to_posix(os.path.join(os.getcwd(), testname))
84  assert res == expected
85
86
87def test_abspath_relative():
88  testname = 'error.json'
89  relative = os.path.join(os.getcwd(), 'tests/specs/with_externals.yaml')
90  res = fs.abspath(testname, relative)
91  expected = fs.to_posix(os.path.join(os.getcwd(), 'tests', 'specs', testname))
92  assert res == expected
93
94
95def test_abspath_relative_dir():
96  testname = 'error.json'
97  relative = os.path.join(os.getcwd(), 'tests', 'specs')
98  res = fs.abspath(testname, relative)
99  expected = fs.to_posix(os.path.join(os.getcwd(), 'tests', 'specs', testname))
100  assert res == expected
101
102
103def test_detect_encoding():
104  # Quick detection should yield utf-8 for the petstore file.
105  assert fs.detect_encoding('tests/specs/petstore.yaml') == 'utf-8'
106
107  # Without defaulting to utf-8, it should also work.
108  assert fs.detect_encoding('tests/specs/petstore.yaml',
109                            default_to_utf8 = False) == 'utf-8'
110
111  # Deep inspection should not change anything because the file size is
112  # too small.
113  assert fs.detect_encoding('tests/specs/petstore.yaml',
114                            default_to_utf8 = False,
115                            read_all = True) == 'utf-8'
116
117  # The UTF-8 file with BOM should be detected properly
118  assert fs.detect_encoding('tests/specs/utf8bom.yaml') == 'utf-8-sig'
119
120
121def test_issue_51_detect_encoding():
122  # This should be UTF-8, but in issue 51 it was reported that it comes back
123  # as iso-8859-2
124
125  # Detection should be ok if the entire file is read
126  assert fs.detect_encoding('tests/specs/issue_51/openapi-part.yaml', read_all = True) == 'utf-8'
127
128  # After the heuristic change, it reads the whole file anyway.
129  assert fs.detect_encoding('tests/specs/issue_51/openapi-part.yaml') == 'utf-8'
130
131  # Specifically re-encoded as iso-8859-2 should fail - but not as
132  # a call to the detect_encoding() function. Instead, we can only return
133  # a badly detected encoding. Chardet sends iso-8859-1 here.
134  assert fs.detect_encoding('tests/specs/issue_51/openapi-part-iso-8859-2.yaml') == 'iso-8859-1'
135
136
137def test_load_nobom():
138  contents = fs.read_file('tests/specs/petstore.yaml')
139  assert contents.index('Swagger Petstore') >= 0, 'File reading failed!'
140
141
142def test_load_utf8bom():
143  contents = fs.read_file('tests/specs/utf8bom.yaml')
144  assert contents.index('söme välüe') >= 0, 'UTF-8 BOM handling failed!'
145
146
147def test_load_utf8bom_override():
148  with pytest.raises(UnicodeDecodeError):
149    fs.read_file('tests/specs/utf8bom.yaml', 'ascii')
150
151
152def test_write_file(tmpdir):
153  with sandbox.sandbox(tmpdir):
154    test_text = 'söme täxt'
155    fs.write_file('test.out', test_text)
156
157    # File must have been written
158    files = [f for f in os.listdir('.') if os.path.isfile(f)]
159    assert 'test.out' in files
160
161    # File contents must work
162    contents = fs.read_file('test.out')
163    assert test_text == contents
164
165
166def test_write_file_bom(tmpdir):
167  with sandbox.sandbox(tmpdir):
168    test_text = 'söme täxt'
169    fs.write_file('test.out', test_text, 'utf-8-sig')
170
171    # File must have been written
172    files = [f for f in os.listdir('.') if os.path.isfile(f)]
173    assert 'test.out' in files
174
175    # Encoding must match the one we've given
176    encoding = fs.detect_encoding('test.out')
177    assert encoding == 'utf-8-sig'
178
179    # File contents must work
180    contents = fs.read_file('test.out')
181    assert test_text == contents
182
183
184def test_valid_pathname():
185  # A URL should not be valid
186  from prance.util.fs import is_pathname_valid
187  assert False == is_pathname_valid('\x00o.bar.org')
188
189  # However, the current path should be.
190  import os
191  assert True == is_pathname_valid(os.getcwd())
192
193  # Can't put non-strings into this function
194  assert True == is_pathname_valid('foo')
195  assert False == is_pathname_valid(123)
196
197  # Can't accept too long components
198  assert False == is_pathname_valid('a'*256)
199