@@ -1339,6 +1339,195 @@ This achievement represents a **dramatic improvement from widespread registry fa
13391339
13401340**The 100% test success rate demonstrates that the shared registry pattern successfully eliminated registry conflicts while maintaining all architectural principles of the MetaObjects framework.**
13411341
1342+ ## 🧪 **UNIT TEST SETUP GUIDELINES (CRITICAL FOR FUTURE DEVELOPMENT)**
1343+
1344+ ### 🚨 **MANDATORY TESTING PATTERNS TO PREVENT SERVICELOADER CONFLICTS**
1345+
1346+ **CONTEXT**: ServiceLoader discovery behaves differently on Windows vs Linux, causing duplicate constraint registrations that break tests on GitHub Actions. These patterns are REQUIRED for all new test classes.
1347+
1348+ #### **✅ DEFAULT PATTERN: SharedRegistryTestBase (Use This for 95% of Tests)**
1349+
1350+ ```java
1351+ // ✅ CORRECT - Use this pattern for all standard tests
1352+ public class YourNewTest extends SharedRegistryTestBase {
1353+
1354+ @Test
1355+ public void testSomething() {
1356+ // Use sharedRegistry instead of MetaDataRegistry.getInstance()
1357+ MetaDataRegistry registry = getSharedRegistry();
1358+
1359+ // Your test logic here - registry is shared and stable
1360+ TypeDefinition def = registry.getTypeDefinition("field", "string");
1361+ assertNotNull("Type should be registered", def);
1362+ }
1363+ }
1364+ ```
1365+
1366+ ** WHY** : Extends SharedRegistryTestBase which provides a single static MetaDataRegistry shared across ALL tests, preventing registry conflicts.
1367+
1368+ #### ** ⚠️ ISOLATED PATTERN: For Tests That Manipulate Registry**
1369+
1370+ ``` java
1371+ // ⚠️ USE SPARINGLY - Only for tests that must clear/manipulate registry
1372+ @IsolatedTest (" Clears and restores shared MetaDataRegistry state" )
1373+ public class RegistryManipulationTest extends SharedRegistryTestBase {
1374+
1375+ private Map<String , TypeDefinition > backupRegistry;
1376+
1377+ @Before
1378+ public void setUp () {
1379+ MetaDataRegistry registry = getSharedRegistry();
1380+
1381+ // CRITICAL: Disable strict duplicate detection for isolation
1382+ registry. disableStrictDuplicateDetection();
1383+
1384+ // Backup existing registrations
1385+ backupRegistry = new HashMap<> ();
1386+ for (String typeName : registry. getRegisteredTypeNames()) {
1387+ // Store backup...
1388+ }
1389+
1390+ // Clear for isolated testing
1391+ registry. clear();
1392+ }
1393+
1394+ @After
1395+ public void tearDown () {
1396+ MetaDataRegistry registry = getSharedRegistry();
1397+ if (registry != null ) {
1398+ registry. clear();
1399+ restoreRegistryFromBackup();
1400+
1401+ // CRITICAL: Re-enable strict duplicate detection
1402+ registry. enableStrictDuplicateDetection();
1403+ }
1404+ }
1405+ }
1406+ ```
1407+
1408+ ** USE CASES** : Tests that need to clear registry, test registration logic, or manipulate global registry state.
1409+
1410+ ### 🚫 ** ANTI-PATTERNS TO NEVER USE**
1411+
1412+ #### ** ❌ BROKEN PATTERN: Direct MetaDataRegistry.getInstance()**
1413+
1414+ ``` java
1415+ // ❌ WRONG - Causes ServiceLoader conflicts on GitHub Actions
1416+ public class BrokenTest {
1417+
1418+ @Test
1419+ public void testSomething () {
1420+ // ❌ This causes platform-specific failures
1421+ MetaDataRegistry registry = MetaDataRegistry . getInstance();
1422+
1423+ // ❌ This fails with "expected:<1> but was:<2>" on Linux
1424+ List<Constraint > constraints = registry. getAllValidationConstraints();
1425+ assertEquals(1 , constraints. size()); // Fails due to duplicates
1426+ }
1427+ }
1428+ ```
1429+
1430+ ** WHY BROKEN** : ServiceLoader discovers providers multiple times on Linux/GitHub Actions, causing duplicate constraint registrations.
1431+
1432+ #### ** ❌ BROKEN PATTERN: Manual Registry Creation**
1433+
1434+ ``` java
1435+ // ❌ WRONG - Creates separate registry instances
1436+ public class AnotherBrokenTest {
1437+
1438+ @BeforeClass
1439+ public static void setUpClass () {
1440+ // ❌ Creates conflicts with other tests
1441+ MetaDataRegistry separateRegistry = new MetaDataRegistry ();
1442+ // This doesn't integrate with shared test infrastructure
1443+ }
1444+ }
1445+ ```
1446+
1447+ ### 🔧 ** INTELLIGENT ERROR DETECTION SYSTEM**
1448+
1449+ The framework includes intelligent duplicate detection that provides helpful error messages when tests are set up incorrectly:
1450+
1451+ ``` java
1452+ // Error message developers see when using broken patterns:
1453+ DUPLICATE CONSTRAINT DETECTED : Constraint ID ' metadata.base.objects' already registered!
1454+
1455+ This usually indicates a test registry isolation problem:
1456+ ❌ Existing : PlacementConstraint [metadata. base can contain objects]
1457+ ❌ Attempted : PlacementConstraint [metadata. base can contain objects]
1458+
1459+ SOLUTION : If this is a test class, extend SharedRegistryTestBase instead of:
1460+ ❌ MetaDataRegistry registry = MetaDataRegistry . getInstance();
1461+ ✅ public class YourTest extends SharedRegistryTestBase { ... }
1462+
1463+ This prevents registry conflicts between tests on different platforms (Windows / Linux ).
1464+ See CLAUDE . md for detailed explanation of the shared registry pattern.
1465+ ```
1466+
1467+ ### 🌍 ** PLATFORM DIFFERENCES EXPLAINED**
1468+
1469+ #### ** Windows Behavior**
1470+ - ServiceLoader typically discovers each MetaDataTypeProvider once
1471+ - Constraint counts remain consistent (expected behavior)
1472+ - Tests pass locally during development
1473+
1474+ #### ** Linux/GitHub Actions Behavior**
1475+ - ServiceLoader may discover providers multiple times due to classloader differences
1476+ - Causes duplicate constraint registrations
1477+ - Results in "expected:<1> but was:<2>" test failures
1478+ - Breaks CI/CD builds
1479+
1480+ #### ** Solution Architecture**
1481+ The SharedRegistryTestBase pattern eliminates platform differences by:
1482+ 1 . ** Single Static Registry** : One registry instance shared across all tests
1483+ 2 . ** Controlled Initialization** : Registry initialized once before any tests run
1484+ 3 . ** Predictable State** : Same registry state regardless of platform
1485+ 4 . ** Conflict Prevention** : No teardown/recreation between tests
1486+
1487+ ### 📝 ** TESTING CHECKLIST FOR NEW TESTS**
1488+
1489+ ** Before creating any new test class:**
1490+
1491+ ✅ ** Does your test need to manipulate the registry?**
1492+ - ** NO** : Use ` extends SharedRegistryTestBase ` (standard pattern)
1493+ - ** YES** : Use ` @IsolatedTest ` pattern with strict duplicate detection controls
1494+
1495+ ✅ ** Are you accessing MetaDataRegistry?**
1496+ - ** Use** : ` getSharedRegistry() ` method from base class
1497+ - ** NEVER** : ` MetaDataRegistry.getInstance() ` directly
1498+
1499+ ✅ ** Are you testing constraint-related functionality?**
1500+ - ** Expect** : Consistent constraint counts across platforms
1501+ - ** Use** : Shared registry to avoid duplicate registrations
1502+
1503+ ✅ ** Are you creating test data or metadata?**
1504+ - ** Follow** : Naming patterns that comply with identifier constraints
1505+ - ** Use** : SharedRegistryTestBase for predictable type availability
1506+
1507+ ### 🎯 ** EXAMPLES OF CONVERTED TESTS**
1508+
1509+ ** Successfully converted test classes that now follow these patterns:**
1510+ - ✅ ` StringArrayAttributeRegexValidationTest ` - SharedRegistryTestBase pattern
1511+ - ✅ ` UniquenessConstraintTest ` - SharedRegistryTestBase pattern
1512+ - ✅ ` AllMetaDataTypesRegistrationTest ` - SharedRegistryTestBase pattern
1513+ - ✅ ` BasicRegistryTest ` - @IsolatedTest pattern with strict controls
1514+ - ✅ ` StaticRegistrationTest ` - @IsolatedTest pattern with strict controls
1515+
1516+ ** Test Results After Conversion:**
1517+ - ** Before** : 199 tests → 66 failures, 33 errors (~ 50% passing)
1518+ - ** After** : 227 tests → 0 failures, 0 errors (100% PASSING ✅)
1519+
1520+ ### 🚨 ** CRITICAL SUCCESS FACTORS**
1521+
1522+ 1 . ** ALWAYS extend SharedRegistryTestBase** unless you absolutely need registry isolation
1523+ 2 . ** NEVER use MetaDataRegistry.getInstance()** directly in tests
1524+ 3 . ** ALWAYS use getSharedRegistry()** from the base class
1525+ 4 . ** DISABLE strict duplicate detection** only in @IsolatedTest setUp()
1526+ 5 . ** RE-ENABLE strict duplicate detection** in @IsolatedTest tearDown()
1527+ 6 . ** BACKUP and RESTORE** registry state in isolated tests
1528+
1529+ ** Following these patterns ensures tests pass consistently on both Windows development machines and Linux GitHub Actions runners.**
1530+
13421531## 🎉 ** ARCHITECTURAL REFACTORING COMPLETION STATUS**
13431532
13441533** ✅ PHASE 1: Preparation** - Completed
0 commit comments