@@ -1754,6 +1754,96 @@ public async Task ContentFiles_VerifyPPInLockFile()
17541754 Assert . Equal ( "False" , helperCsItem . Properties [ "copyToOutput" ] ) ;
17551755 }
17561756
1757+ [ Fact ]
1758+ public async Task ContentFiles_ExactMatchAndWildcardPatterns ( )
1759+ {
1760+ // Arrange
1761+ // This test verifies the optimization for exact matches (no wildcards) and wildcards work correctly
1762+ var logger = new TestLogger ( ) ;
1763+ var framework = "net46" ;
1764+
1765+ using ( var workingDir = TestDirectory . Create ( ) )
1766+ {
1767+ var repository = Path . Combine ( workingDir , "repository" ) ;
1768+ Directory . CreateDirectory ( repository ) ;
1769+ var projectDir = Path . Combine ( workingDir , "project" ) ;
1770+ Directory . CreateDirectory ( projectDir ) ;
1771+ var packagesDir = Path . Combine ( workingDir , "packages" ) ;
1772+ Directory . CreateDirectory ( packagesDir ) ;
1773+
1774+ var file = new FileInfo ( Path . Combine ( repository , "packageA.1.0.0.nupkg" ) ) ;
1775+
1776+ using ( var zip = new ZipArchive ( File . Create ( file . FullName ) , ZipArchiveMode . Create ) )
1777+ {
1778+ // Add multiple content files
1779+ zip . AddEntry ( "contentFiles/any/any/exact.txt" , new byte [ ] { 0 } ) ;
1780+ zip . AddEntry ( "contentFiles/any/any/wildcard1.txt" , new byte [ ] { 0 } ) ;
1781+ zip . AddEntry ( "contentFiles/any/any/wildcard2.txt" , new byte [ ] { 0 } ) ;
1782+ zip . AddEntry ( "contentFiles/any/any/excluded.txt" , new byte [ ] { 0 } ) ;
1783+
1784+ zip . AddEntry ( "packageA.nuspec" , @"<?xml version=""1.0"" encoding=""utf-8""?>
1785+ <package xmlns=""http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd"">
1786+ <metadata>
1787+ <id>packageA</id>
1788+ <version>1.0.0</version>
1789+ <title />
1790+ <contentFiles>
1791+ <!-- Exact match - should use fast path -->
1792+ <files include=""any/any/exact.txt"" buildAction=""Content"" copyToOutput=""true"" />
1793+ <!-- Wildcard pattern - should use globbing -->
1794+ <files include=""any/any/wildcard*.txt"" buildAction=""None"" />
1795+ <!-- Wildcard with exclude - should use globbing -->
1796+ <files include=""any/any/*.txt"" exclude=""any/any/excluded.txt"" buildAction=""Compile"" />
1797+ </contentFiles>
1798+ </metadata>
1799+ </package>" , Encoding . UTF8 ) ;
1800+ }
1801+
1802+ var sources = new List < PackageSource > ( ) ;
1803+ sources . Add ( new PackageSource ( repository ) ) ;
1804+
1805+ var configJson = GetConfigWithFrameworkAndDependency ( framework ) ;
1806+
1807+ var specPath = Path . Combine ( projectDir , "TestProject" , "project.json" ) ;
1808+ var spec = JsonPackageSpecReader . GetPackageSpec ( configJson . ToString ( ) , "TestProject" , specPath ) . WithTestRestoreMetadata ( ) ;
1809+
1810+ var request = new TestRestoreRequest ( spec , sources , packagesDir , logger ) ;
1811+ request . LockFilePath = Path . Combine ( projectDir , "project.lock.json" ) ;
1812+
1813+ var command = new RestoreCommand ( request ) ;
1814+
1815+ // Act
1816+ var result = await command . ExecuteAsync ( ) ;
1817+ await result . CommitAsync ( logger , CancellationToken . None ) ;
1818+
1819+ var target = result . LockFile . GetTarget ( NuGetFramework . Parse ( framework ) , null ) ;
1820+ var contentFiles = target . Libraries . Single ( ) . ContentFiles ;
1821+
1822+ // Assert
1823+ Assert . Equal ( 0 , result . CompatibilityCheckResults . Sum ( checkResult => checkResult . Issues . Count ) ) ;
1824+ Assert . Equal ( 0 , logger . Errors ) ;
1825+ Assert . Equal ( 0 , logger . Warnings ) ;
1826+ Assert . Equal ( 4 , contentFiles . Count ) ;
1827+
1828+ // Verify exact match file (fast path)
1829+ var exactFile = contentFiles . Single ( item => item . Path == "contentFiles/any/any/exact.txt" ) ;
1830+ Assert . Equal ( "Content" , exactFile . Properties [ "buildAction" ] ) ;
1831+ Assert . Equal ( "True" , exactFile . Properties [ "copyToOutput" ] ) ;
1832+
1833+ // Verify wildcard matched files (slow path)
1834+ var wildcard1File = contentFiles . Single ( item => item . Path == "contentFiles/any/any/wildcard1.txt" ) ;
1835+ Assert . Equal ( "None" , wildcard1File . Properties [ "buildAction" ] ) ;
1836+
1837+ var wildcard2File = contentFiles . Single ( item => item . Path == "contentFiles/any/any/wildcard2.txt" ) ;
1838+ Assert . Equal ( "None" , wildcard2File . Properties [ "buildAction" ] ) ;
1839+
1840+ // Verify excluded file is not matched but appears with the last matching rule
1841+ var excludedFile = contentFiles . Single ( item => item . Path == "contentFiles/any/any/excluded.txt" ) ;
1842+ // This file matches the wildcard pattern "wildcard*.txt" is None, not excluded by the last rule
1843+ Assert . Equal ( "None" , excludedFile . Properties [ "buildAction" ] ) ;
1844+ }
1845+ }
1846+
17571847 private async Task < RestoreResult > StandardSetup (
17581848 string framework ,
17591849 NuGet . Common . ILogger logger )
0 commit comments