@@ -1743,6 +1743,181 @@ def test_deeply_nested_choice_objects(self):
17431743 assert not result .has_errors ()
17441744
17451745
1746+ class TestDoubleUnderscoreTempVariables :
1747+ """Test suite for __ prefixed temp variable handling in validation.
1748+
1749+ Snowfakery supports temporary/hidden variables prefixed with __ (double underscore).
1750+ These should be validated correctly and accessible both within the same object
1751+ and via cross-object references.
1752+ """
1753+
1754+ def test_dunder_variable_within_same_object (self ):
1755+ """Test that __ prefixed variables work within the same object"""
1756+ yaml = """
1757+ - snowfakery_version: 3
1758+ - object: User
1759+ fields:
1760+ __gender_folder:
1761+ random_choice: [men, women]
1762+ FirstName: ${{ fake.FirstNameMale() if __gender_folder == 'men' else fake.FirstNameFemale() }}
1763+ """
1764+ result = generate (StringIO (yaml ), validate_only = True )
1765+ assert not result .has_errors ()
1766+
1767+ def test_dunder_variable_cross_object_reference (self ):
1768+ """Test that __ prefixed variables can be accessed via object reference"""
1769+ yaml = """
1770+ - snowfakery_version: 3
1771+ - object: User
1772+ nickname: tech_user
1773+ fields:
1774+ __gender_folder:
1775+ random_choice: [men, women]
1776+ FirstName:
1777+ fake: FirstName
1778+
1779+ - object: ServiceResource
1780+ fields:
1781+ Name: ${{tech_user.FirstName}}
1782+ ProfilePicture: "https://example.com/${{tech_user.__gender_folder}}/photo.jpg"
1783+ """
1784+ result = generate (StringIO (yaml ), validate_only = True )
1785+ assert not result .has_errors ()
1786+
1787+ def test_multiple_dunder_variables (self ):
1788+ """Test that multiple __ prefixed variables work together"""
1789+ yaml = """
1790+ - snowfakery_version: 3
1791+ - object: Item
1792+ fields:
1793+ __idx: ${{child_index}}
1794+ __multiplier: 10
1795+ ComputedValue: ${{ __idx * __multiplier }}
1796+ """
1797+ result = generate (StringIO (yaml ), validate_only = True )
1798+ assert not result .has_errors ()
1799+
1800+ def test_dunder_variable_in_nested_friends (self ):
1801+ """Test that __ prefixed variables work in nested friend objects"""
1802+ yaml = """
1803+ - snowfakery_version: 3
1804+ - object: Account
1805+ count: 2
1806+ nickname: parent_account
1807+ fields:
1808+ __region:
1809+ random_choice: [North, South, East, West]
1810+ Name: ${{__region}} Region Account
1811+ friends:
1812+ - object: Contact
1813+ nickname: account_contact
1814+ fields:
1815+ __department:
1816+ random_choice: [Sales, Engineering, Marketing]
1817+ FirstName:
1818+ fake: FirstName
1819+ Department: ${{__department}}
1820+ friends:
1821+ - object: Task
1822+ fields:
1823+ Subject: Task for ${{account_contact.FirstName}} in ${{account_contact.__department}}
1824+ """
1825+ result = generate (StringIO (yaml ), validate_only = True )
1826+ assert not result .has_errors ()
1827+
1828+ def test_dunder_variable_with_integer_operations (self ):
1829+ """Test that __ prefixed variables work with integer operations"""
1830+ yaml = """
1831+ - snowfakery_version: 3
1832+ - object: WorkOrder
1833+ nickname: work_order
1834+ fields:
1835+ __wo_idx: ${{child_index}}
1836+ Subject: Work Order ${{__wo_idx}}
1837+ friends:
1838+ - object: ServiceAppointment
1839+ fields:
1840+ __start_hour: ${{ 9 + (int(work_order.__wo_idx) % 8) }}
1841+ ScheduledTime: "${{ '%02d' % __start_hour }}:00"
1842+ """
1843+ result = generate (StringIO (yaml ), validate_only = True )
1844+ assert not result .has_errors ()
1845+
1846+ def test_dunder_variable_conditional_logic (self ):
1847+ """Test that __ prefixed variables work in conditional logic"""
1848+ yaml = """
1849+ - snowfakery_version: 3
1850+ - object: Record
1851+ fields:
1852+ __type_selector:
1853+ random_number:
1854+ min: 1
1855+ max: 3
1856+ Type: ${{ 'Premium' if __type_selector == 1 else ('Standard' if __type_selector == 2 else 'Basic') }}
1857+ """
1858+ result = generate (StringIO (yaml ), validate_only = True )
1859+ assert not result .has_errors ()
1860+
1861+ def test_dunder_variable_not_accessible_before_definition (self ):
1862+ """Test that __ prefixed variables are not accessible before they are defined"""
1863+ yaml = """
1864+ - snowfakery_version: 3
1865+ - object: Record
1866+ fields:
1867+ EarlyField: ${{__later_var}}
1868+ __later_var: some_value
1869+ """
1870+ with pytest .raises (DataGenValidationError ) as exc_info :
1871+ generate (StringIO (yaml ), validate_only = True )
1872+
1873+ # Should report undefined variable
1874+ assert "__later_var" in str (exc_info .value )
1875+
1876+ def test_dunder_variable_in_random_choice_context (self ):
1877+ """Test __ prefixed variables with random_choice as commonly used"""
1878+ yaml = """
1879+ - snowfakery_version: 3
1880+ - object: Territory
1881+ fields:
1882+ __hub_name:
1883+ random_choice: ["Los Angeles", "San Francisco", "Seattle", "Denver"]
1884+ Name: ${{__hub_name}} Hub
1885+ City: ${{__hub_name}}
1886+ """
1887+ result = generate (StringIO (yaml ), validate_only = True )
1888+ assert not result .has_errors ()
1889+
1890+ def test_dunder_variable_complex_nested_scenario (self ):
1891+ """Test complex scenario with multiple levels of nesting and __ prefixed variables"""
1892+ yaml = """
1893+ - snowfakery_version: 3
1894+ - object: Company
1895+ nickname: company
1896+ count: 2
1897+ fields:
1898+ __company_type:
1899+ random_choice: [Tech, Finance, Healthcare]
1900+ Name: ${{__company_type}} Corp
1901+ friends:
1902+ - object: Department
1903+ nickname: dept
1904+ count: 3
1905+ fields:
1906+ __dept_code: ${{ 'D' + str(child_index + 1) }}
1907+ Code: ${{__dept_code}}
1908+ CompanyType: ${{company.__company_type}}
1909+ friends:
1910+ - object: Employee
1911+ count: 2
1912+ fields:
1913+ __emp_id: ${{ dept.__dept_code + '-' + str(child_index + 1) }}
1914+ EmployeeId: ${{__emp_id}}
1915+ DeptCode: ${{dept.Code}}
1916+ """
1917+ result = generate (StringIO (yaml ), validate_only = True )
1918+ assert not result .has_errors ()
1919+
1920+
17461921class TestMockThisKeyword :
17471922 """Test suite for 'this' keyword validation and MockThis error messages"""
17481923
0 commit comments