Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions Lib/test/test_aix_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import unittest
from unittest import mock
from test import support
import _aix_support

class TestAIXSupport(unittest.TestCase):
def test_aix_vrtl(self):
# _aix_vrtl takes the last character of the version string as the first element of the list
self.assertEqual(_aix_support._aix_vrtl("7.1.4.34"), [7, 1, 4])
self.assertEqual(_aix_support._aix_vrtl("6.1.0.0"), [6, 1, 0])
self.assertEqual(_aix_support._aix_vrtl("1.2.3.4"), [1, 2, 3])

def test_aix_tag(self):
with mock.patch("sys.maxsize", 2**31 - 1):
self.assertEqual(_aix_support._aix_tag([6, 1, 7], 1415), "aix-6107-1415-32")
with mock.patch("sys.maxsize", 2**63 - 1):
self.assertEqual(_aix_support._aix_tag([6, 1, 7], 1415), "aix-6107-1415-64")
# Default build date
with mock.patch("sys.maxsize", 2**63 - 1):
self.assertEqual(_aix_support._aix_tag([7, 1, 0], 0), "aix-7100-9988-64")

@mock.patch("subprocess.check_output")
def test_aix_bos_rte(self, mock_check_output):
mock_check_output.return_value = b"something:something:7.1.4.34:something:something:something:1806"
vrmf, bd = _aix_support._aix_bos_rte()
self.assertEqual(vrmf, "7.1.4.34")
self.assertEqual(bd, 1806)

# No build date
mock_check_output.return_value = b"something:something:7.1.4.34:something:something:something:"
vrmf, bd = _aix_support._aix_bos_rte()
self.assertEqual(bd, 9988)

@mock.patch("_aix_support._aix_bos_rte")
@mock.patch("sys.maxsize", 2**63 - 1)
def test_aix_platform(self, mock_bos_rte):
mock_bos_rte.return_value = ("7.1.4.34", 1806)
self.assertEqual(_aix_support.aix_platform(), "aix-7104-1806-64")

@mock.patch("sysconfig.get_config_var")
def test_aix_bgt(self, mock_get_config_var):
mock_get_config_var.return_value = "powerpc-ibm-aix7.1.4.0"
self.assertEqual(_aix_support._aix_bgt(), [7, 1, 4])

mock_get_config_var.return_value = None
with self.assertRaises(ValueError):
_aix_support._aix_bgt()

@mock.patch("sysconfig.get_config_var")
@mock.patch("_aix_support._aix_bgt")
@mock.patch("sys.maxsize", 2**63 - 1)
def test_aix_buildtag(self, mock_aix_bgt, mock_get_config_var):
mock_aix_bgt.return_value = [7, 1, 4]
mock_get_config_var.return_value = "1806"
self.assertEqual(_aix_support.aix_buildtag(), "aix-7104-1806-64")

mock_get_config_var.return_value = "invalid"
with self.assertRaises(ValueError):
_aix_support.aix_buildtag()

if __name__ == "__main__":
unittest.main()
62 changes: 62 additions & 0 deletions Lib/test/test_ios_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import unittest
from unittest import mock
from test import support

# Import the module under test. It's already in the path when running via regrtest.
import _ios_support

class TestIOSSupport(unittest.TestCase):
def test_get_platform_ios_no_objc(self):
with mock.patch("_ios_support.objc", None):
with mock.patch("sys.implementation._multiarch", "arm64-ios"):
self.assertIsNone(_ios_support.get_platform_ios())

def test_get_platform_ios_simulator(self):
# We need to mock objc and its methods
mock_objc = mock.Mock()
mock_objc.objc_getClass.return_value = 1
mock_objc.sel_registerName.return_value = 2

# mock_objc.objc_msgSend.side_effect is used multiple times
mock_objc.objc_msgSend.side_effect = [
10, # device
20, # systemVersion
30, # systemName
40, # model
b"iOS", # system
b"15.0", # release
b"iPhone" # model
]

# We also need to mock c_void_p and c_char_p if they are missing in the environment
# as the module uses them from its own namespace.
with mock.patch("_ios_support.objc", mock_objc):
with mock.patch("_ios_support.c_void_p", "c_void_p", create=True):
with mock.patch("_ios_support.c_char_p", "c_char_p", create=True):
with mock.patch("sys.implementation._multiarch", "x86_64-ios-simulator"):
result = _ios_support.get_platform_ios()
self.assertEqual(result, ("iOS", "15.0", "iPhone", True))

def test_get_platform_ios_device(self):
mock_objc = mock.Mock()
mock_objc.objc_getClass.return_value = 1
mock_objc.sel_registerName.return_value = 2
mock_objc.objc_msgSend.side_effect = [
10, # device
20, # systemVersion
30, # systemName
40, # model
b"iOS", # system
b"15.0", # release
b"iPhone" # model
]

with mock.patch("_ios_support.objc", mock_objc):
with mock.patch("_ios_support.c_void_p", "c_void_p", create=True):
with mock.patch("_ios_support.c_char_p", "c_char_p", create=True):
with mock.patch("sys.implementation._multiarch", "arm64-ios"):
result = _ios_support.get_platform_ios()
self.assertEqual(result, ("iOS", "15.0", "iPhone", False))

if __name__ == "__main__":
unittest.main()
218 changes: 218 additions & 0 deletions Lib/test/test_markupbase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import unittest
from _markupbase import ParserBase

class MockParser(ParserBase):
def __init__(self):
super().__init__()
self.rawdata = ""
self.reset()
self.decls = []
self.comments = []

def handle_decl(self, decl):
self.decls.append(decl)

def unknown_decl(self, data):
self.decls.append(data)

def handle_comment(self, data):
self.comments.append(data)

class TestMarkupBase(unittest.TestCase):
def test_init_fail(self):
with self.assertRaisesRegex(RuntimeError, "_markupbase.ParserBase must be subclassed"):
ParserBase()

def test_updatepos(self):
parser = MockParser()
parser.rawdata = "abc\ndef\nghi"
parser.updatepos(0, 4)
self.assertEqual(parser.getpos(), (2, 0))
parser.updatepos(4, 6)
self.assertEqual(parser.getpos(), (2, 2))
parser.updatepos(6, 8)
self.assertEqual(parser.getpos(), (3, 0))

# No-op if i >= j
pos = parser.getpos()
parser.updatepos(8, 8)
self.assertEqual(parser.getpos(), pos)
parser.updatepos(9, 8)
self.assertEqual(parser.getpos(), pos)

def test_parse_comment(self):
parser = MockParser()
parser.rawdata = "<!--comment-->"
n = parser.parse_comment(0)
self.assertEqual(n, len(parser.rawdata))
self.assertEqual(parser.comments, ["comment"])

# No report
parser = MockParser()
parser.rawdata = "<!--comment-->"
n = parser.parse_comment(0, report=0)
self.assertEqual(n, len(parser.rawdata))
self.assertEqual(parser.comments, [])

# Incomplete
parser = MockParser()
parser.rawdata = "<!--comment"
n = parser.parse_comment(0)
self.assertEqual(n, -1)

# Unexpected call
parser = MockParser()
parser.rawdata = "NOT A COMMENT"
with self.assertRaises(AssertionError):
parser.parse_comment(0)

def test_parse_declaration(self):
parser = MockParser()
parser.rawdata = "<!DOCTYPE html>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))
self.assertEqual(parser.decls, ["DOCTYPE html"])

# Empty comment <!>
parser = MockParser()
parser.rawdata = "<!>"
n = parser.parse_declaration(0)
self.assertEqual(n, 3)

# Incomplete
parser = MockParser()
parser.rawdata = "<!-"
n = parser.parse_declaration(0)
self.assertEqual(n, -1)

parser = MockParser()
parser.rawdata = "<!"
n = parser.parse_declaration(0)
self.assertEqual(n, -1)

# Unexpected call
parser = MockParser()
parser.rawdata = "NOT A DECL"
with self.assertRaises(AssertionError):
parser.parse_declaration(0)

def test_parse_marked_section(self):
parser = MockParser()
parser.rawdata = "<![CDATA[content]]>"
n = parser.parse_marked_section(0)
self.assertEqual(n, len(parser.rawdata))
self.assertEqual(parser.decls, ["CDATA[content"])

# MS Office extension
parser = MockParser()
parser.rawdata = "<![if word]>content<![endif]>"
n = parser.parse_marked_section(0)
self.assertEqual(n, len("<![if word]>"))
self.assertEqual(parser.decls, ["if word"])

# Incomplete
parser = MockParser()
parser.rawdata = "<![CDATA[content"
n = parser.parse_marked_section(0)
self.assertEqual(n, -1)

# Unexpected call
parser = MockParser()
parser.rawdata = "<!NOT MARKED"
with self.assertRaises(AssertionError):
parser.parse_marked_section(0)

# Unknown keyword
parser = MockParser()
parser.rawdata = "<![UNKNOWN keyword]]>"
with self.assertRaises(AssertionError):
parser.parse_marked_section(0)

def test_doctype_subset(self):
parser = MockParser()
parser.rawdata = "<!DOCTYPE html [ <!ELEMENT foo ANY> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))
self.assertEqual(parser.decls, ["DOCTYPE html [ <!ELEMENT foo ANY> ]"])

# Complex subset
parser = MockParser()
parser.rawdata = "<!DOCTYPE doc [ <!ENTITY e 'v'> <!ATTLIST a attr CDATA #REQUIRED> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

# Subset with comments
parser = MockParser()
parser.rawdata = "<!DOCTYPE doc [ <!-- comment --> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

# Subset with percentage (parameter entity)
parser = MockParser()
parser.rawdata = "<!DOCTYPE doc [ %name; ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

def test_scan_name_errors(self):
parser = MockParser()
parser.rawdata = "<!DOCTYPE " # incomplete name
n = parser.parse_declaration(0)
self.assertEqual(n, -1)

parser.rawdata = "<! " # not a name
with self.assertRaises(AssertionError):
parser.parse_declaration(0)

def test_parse_doctype_element(self):
parser = MockParser()
parser.rawdata = "<!ELEMENT name ANY>"
n = parser.parse_declaration(0)
self.assertEqual(parser.decls, ["ELEMENT name ANY"])

def test_parse_doctype_attlist(self):
parser = MockParser()
# Simplified attlist: name type [value] [#constraint]
parser.rawdata = "<!DOCTYPE doc [ <!ATTLIST el attr CDATA #IMPLIED> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

# Enumerated type
parser.rawdata = "<!DOCTYPE doc [ <!ATTLIST el attr (a|b) 'a'> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

def test_parse_doctype_notation(self):
parser = MockParser()
parser.rawdata = "<!DOCTYPE doc [ <!NOTATION n SYSTEM 's'> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

def test_parse_doctype_entity(self):
parser = MockParser()
parser.rawdata = "<!DOCTYPE doc [ <!ENTITY % name 'v'> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

parser.rawdata = "<!DOCTYPE doc [ <!ENTITY name 'v'> ]>"
n = parser.parse_declaration(0)
self.assertEqual(n, len(parser.rawdata))

def test_errors_in_subset(self):
parser = MockParser()
# Unexpected char in subset
parser.rawdata = "<!DOCTYPE doc [ ? ]>"
with self.assertRaises(AssertionError):
parser.parse_declaration(0)

# Unknown declaration in subset
parser.rawdata = "<!DOCTYPE doc [ <!UNKNOWN> ]>"
with self.assertRaises(AssertionError):
parser.parse_declaration(0)

# Unexpected char after subset
parser.rawdata = "<!DOCTYPE doc [ ] ? >"
with self.assertRaises(AssertionError):
parser.parse_declaration(0)

if __name__ == "__main__":
unittest.main()
17 changes: 17 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ On Unix, Linux, BSD, macOS, and Cygwin::

This will install Python as ``python3``.

Quick Start for Contributors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1. **Clone the repository:**
``git clone https://github.com/python/cpython.git``
2. **Build Python:**
``./configure --with-pydebug && make -j``
3. **Run tests:**
- To run all tests: ``./python -m test``
- To run a specific test: ``./python -m test test_os``
4. **Create a virtual environment for development:**
``./python -m venv venv && source venv/bin/activate``
5. **Install development tools:**
``python -m pip install pre-commit ruff``
6. **Install pre-commit hooks:**
``pre-commit install``

You can pass many options to the configure script; run ``./configure --help``
to find out more. On macOS case-insensitive file systems and on Cygwin,
the executable is called ``python.exe``; elsewhere it's just ``python``.
Expand Down