@@ -1863,6 +1863,236 @@ and limitations under the License.''');
18631863 }),
18641864 );
18651865
1866+ test (
1867+ 'filters transitive dependencies in workspace correctly' ,
1868+ withRunner ((commandRunner, logger, pubUpdater, printLogs) async {
1869+ // Create workspace root pubspec.yaml
1870+ File (path.join (tempDirectory.path, 'pubspec.yaml' )).writeAsStringSync (
1871+ _workspaceRootPubspecContent,
1872+ );
1873+
1874+ // Create workspace member directories
1875+ final appDir = Directory (
1876+ path.join (tempDirectory.path, 'packages' , 'app' ),
1877+ )..createSync (recursive: true );
1878+ File (path.join (appDir.path, 'pubspec.yaml' )).writeAsStringSync (
1879+ _workspaceMemberAppPubspecContent,
1880+ );
1881+
1882+ final sharedDir = Directory (
1883+ path.join (tempDirectory.path, 'packages' , 'shared' ),
1884+ )..createSync (recursive: true );
1885+ File (path.join (sharedDir.path, 'pubspec.yaml' )).writeAsStringSync (
1886+ _workspaceMemberSharedPubspecContent,
1887+ );
1888+
1889+ // Create pubspec.lock with transitive dependencies
1890+ File (
1891+ path.join (tempDirectory.path, pubspecLockBasename),
1892+ ).writeAsStringSync (_workspacePubspecLockWithTransitiveContent);
1893+
1894+ when (
1895+ () => packageConfig.packages,
1896+ ).thenReturn ([yamlConfigPackage]);
1897+ when (() => detectorResult.matches).thenReturn ([mitLicenseMatch]);
1898+
1899+ when (() => logger.progress (any ())).thenReturn (progress);
1900+
1901+ final result = await commandRunner.run (
1902+ [
1903+ ...commandArguments,
1904+ '--dependency-type' ,
1905+ 'transitive' ,
1906+ tempDirectory.path,
1907+ ],
1908+ );
1909+
1910+ verify (
1911+ () => progress.update (
1912+ 'Collecting licenses from 1 out of 1 package' ,
1913+ ),
1914+ ).called (1 );
1915+ verify (
1916+ () => progress.complete (
1917+ '''Retrieved 1 license from 1 package of type: MIT (1).''' ,
1918+ ),
1919+ ).called (1 );
1920+
1921+ expect (result, equals (ExitCode .success.code));
1922+ }),
1923+ );
1924+
1925+ test (
1926+ 'filters direct-overridden dependencies in workspace correctly' ,
1927+ withRunner ((commandRunner, logger, pubUpdater, printLogs) async {
1928+ // Create workspace root pubspec.yaml
1929+ File (path.join (tempDirectory.path, 'pubspec.yaml' )).writeAsStringSync (
1930+ _workspaceRootPubspecContent,
1931+ );
1932+
1933+ // Create workspace member directories
1934+ final appDir = Directory (
1935+ path.join (tempDirectory.path, 'packages' , 'app' ),
1936+ )..createSync (recursive: true );
1937+ File (path.join (appDir.path, 'pubspec.yaml' )).writeAsStringSync (
1938+ _workspaceMemberAppPubspecContent,
1939+ );
1940+
1941+ final sharedDir = Directory (
1942+ path.join (tempDirectory.path, 'packages' , 'shared' ),
1943+ )..createSync (recursive: true );
1944+ File (path.join (sharedDir.path, 'pubspec.yaml' )).writeAsStringSync (
1945+ _workspaceMemberSharedPubspecContent,
1946+ );
1947+
1948+ // Create pubspec.lock with direct-overridden dependencies
1949+ File (
1950+ path.join (tempDirectory.path, pubspecLockBasename),
1951+ ).writeAsStringSync (_workspacePubspecLockWithOverriddenContent);
1952+
1953+ when (
1954+ () => packageConfig.packages,
1955+ ).thenReturn ([pathConfigPackage]);
1956+ when (() => detectorResult.matches).thenReturn ([mitLicenseMatch]);
1957+
1958+ when (() => logger.progress (any ())).thenReturn (progress);
1959+
1960+ final result = await commandRunner.run (
1961+ [
1962+ ...commandArguments,
1963+ '--dependency-type' ,
1964+ 'direct-overridden' ,
1965+ tempDirectory.path,
1966+ ],
1967+ );
1968+
1969+ verify (
1970+ () => progress.update (
1971+ 'Collecting licenses from 1 out of 1 package' ,
1972+ ),
1973+ ).called (1 );
1974+ verify (
1975+ () => progress.complete (
1976+ '''Retrieved 1 license from 1 package of type: MIT (1).''' ,
1977+ ),
1978+ ).called (1 );
1979+
1980+ expect (result, equals (ExitCode .success.code));
1981+ }),
1982+ );
1983+
1984+ test (
1985+ 'handles malformed workspace member pubspec gracefully' ,
1986+ withRunner ((commandRunner, logger, pubUpdater, printLogs) async {
1987+ // Create workspace root pubspec.yaml
1988+ File (path.join (tempDirectory.path, 'pubspec.yaml' )).writeAsStringSync (
1989+ _workspaceRootPubspecContent,
1990+ );
1991+
1992+ // Create workspace member with malformed pubspec
1993+ final appDir = Directory (
1994+ path.join (tempDirectory.path, 'packages' , 'app' ),
1995+ )..createSync (recursive: true );
1996+ File (path.join (appDir.path, 'pubspec.yaml' )).writeAsStringSync (
1997+ 'invalid: yaml: content: [' ,
1998+ );
1999+
2000+ // Create valid shared package
2001+ final sharedDir = Directory (
2002+ path.join (tempDirectory.path, 'packages' , 'shared' ),
2003+ )..createSync (recursive: true );
2004+ File (path.join (sharedDir.path, 'pubspec.yaml' )).writeAsStringSync (
2005+ _workspaceMemberSharedPubspecContent,
2006+ );
2007+
2008+ File (
2009+ path.join (tempDirectory.path, pubspecLockBasename),
2010+ ).writeAsStringSync (_workspacePubspecLockContent);
2011+
2012+ when (
2013+ () => packageConfig.packages,
2014+ ).thenReturn ([cliCompletionConfigPackage]);
2015+ when (() => detectorResult.matches).thenReturn ([mitLicenseMatch]);
2016+
2017+ when (() => logger.progress (any ())).thenReturn (progress);
2018+
2019+ final result = await commandRunner.run (
2020+ [...commandArguments, tempDirectory.path],
2021+ );
2022+
2023+ // Should still work, just skipping the malformed member
2024+ verify (
2025+ () => progress.update (
2026+ 'Collecting licenses from 1 out of 1 package' ,
2027+ ),
2028+ ).called (1 );
2029+
2030+ expect (result, equals (ExitCode .success.code));
2031+ }),
2032+ );
2033+
2034+ test (
2035+ 'handles nested workspaces recursively' ,
2036+ withRunner ((commandRunner, logger, pubUpdater, printLogs) async {
2037+ // Create root workspace pubspec.yaml
2038+ File (path.join (tempDirectory.path, 'pubspec.yaml' )).writeAsStringSync (
2039+ _workspaceRootPubspecContent,
2040+ );
2041+
2042+ // Create first-level workspace member that is also a workspace root
2043+ final appDir = Directory (
2044+ path.join (tempDirectory.path, 'packages' , 'app' ),
2045+ )..createSync (recursive: true );
2046+ File (path.join (appDir.path, 'pubspec.yaml' )).writeAsStringSync (
2047+ _nestedWorkspaceRootPubspecContent,
2048+ );
2049+
2050+ // Create nested workspace member
2051+ final nestedDir = Directory (
2052+ path.join (tempDirectory.path, 'packages' , 'app' , 'nested' , 'pkg' ),
2053+ )..createSync (recursive: true );
2054+ File (path.join (nestedDir.path, 'pubspec.yaml' )).writeAsStringSync (
2055+ _nestedWorkspaceMemberPubspecContent,
2056+ );
2057+
2058+ // Create shared package
2059+ final sharedDir = Directory (
2060+ path.join (tempDirectory.path, 'packages' , 'shared' ),
2061+ )..createSync (recursive: true );
2062+ File (path.join (sharedDir.path, 'pubspec.yaml' )).writeAsStringSync (
2063+ _workspaceMemberSharedPubspecContent,
2064+ );
2065+
2066+ File (
2067+ path.join (tempDirectory.path, pubspecLockBasename),
2068+ ).writeAsStringSync (_nestedWorkspacePubspecLockContent);
2069+
2070+ when (
2071+ () => packageConfig.packages,
2072+ ).thenReturn ([
2073+ veryGoodTestRunnerConfigPackage,
2074+ cliCompletionConfigPackage,
2075+ yamlConfigPackage,
2076+ ]);
2077+ when (() => detectorResult.matches).thenReturn ([mitLicenseMatch]);
2078+
2079+ when (() => logger.progress (any ())).thenReturn (progress);
2080+
2081+ final result = await commandRunner.run (
2082+ [...commandArguments, tempDirectory.path],
2083+ );
2084+
2085+ // Should collect dependencies from all levels including nested
2086+ verify (
2087+ () => progress.complete (
2088+ '''Retrieved 3 licenses from 3 packages of type: MIT (3).''' ,
2089+ ),
2090+ ).called (1 );
2091+
2092+ expect (result, equals (ExitCode .success.code));
2093+ }),
2094+ );
2095+
18662096 test (
18672097 'works with non-workspace projects (backwards compatibility)' ,
18682098 withRunner ((commandRunner, logger, pubUpdater, printLogs) async {
@@ -2138,3 +2368,110 @@ environment:
21382368dependencies:
21392369 very_good_test_runner: ^0.1.0
21402370''' ;
2371+
2372+ /// A pubspec.lock for workspace with transitive dependencies.
2373+ const _workspacePubspecLockWithTransitiveContent = '''
2374+ packages:
2375+ very_good_test_runner:
2376+ dependency: "direct main"
2377+ description:
2378+ name: very_good_test_runner
2379+ sha256: "4d41e5d7677d259b9a1599c78645ac2d36bc2bd6ff7773507bcb0bab41417fe2"
2380+ url: "https://pub.dev"
2381+ source: hosted
2382+ version: "0.1.2"
2383+ yaml:
2384+ dependency: transitive
2385+ description:
2386+ name: yaml
2387+ sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
2388+ url: "https://pub.dev"
2389+ source: hosted
2390+ version: "3.1.2"
2391+ sdks:
2392+ dart: ">=3.10.0 <4.0.0"
2393+
2394+ ''' ;
2395+
2396+ /// A pubspec.lock for workspace with direct-overridden dependencies.
2397+ const _workspacePubspecLockWithOverriddenContent = '''
2398+ packages:
2399+ very_good_test_runner:
2400+ dependency: "direct main"
2401+ description:
2402+ name: very_good_test_runner
2403+ sha256: "4d41e5d7677d259b9a1599c78645ac2d36bc2bd6ff7773507bcb0bab41417fe2"
2404+ url: "https://pub.dev"
2405+ source: hosted
2406+ version: "0.1.2"
2407+ path:
2408+ dependency: "direct overridden"
2409+ description:
2410+ name: path
2411+ sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
2412+ url: "https://pub.dev"
2413+ source: hosted
2414+ version: "1.9.0"
2415+ sdks:
2416+ dart: ">=3.10.0 <4.0.0"
2417+
2418+ ''' ;
2419+
2420+ /// A nested workspace root pubspec.yaml (workspace member that is also a root).
2421+ const _nestedWorkspaceRootPubspecContent = '''
2422+ name: app
2423+
2424+ environment:
2425+ sdk: ^3.6.0
2426+
2427+ workspace:
2428+ - nested/pkg
2429+
2430+ dependencies:
2431+ very_good_test_runner: ^0.1.0
2432+ ''' ;
2433+
2434+ /// A nested workspace member pubspec.yaml.
2435+ const _nestedWorkspaceMemberPubspecContent = '''
2436+ name: nested_pkg
2437+
2438+ environment:
2439+ sdk: ^3.6.0
2440+
2441+ resolution: workspace
2442+
2443+ dependencies:
2444+ yaml: ^3.1.0
2445+ ''' ;
2446+
2447+ /// A pubspec.lock for nested workspace with dependencies from all levels.
2448+ const _nestedWorkspacePubspecLockContent = '''
2449+ packages:
2450+ very_good_test_runner:
2451+ dependency: "direct main"
2452+ description:
2453+ name: very_good_test_runner
2454+ sha256: "4d41e5d7677d259b9a1599c78645ac2d36bc2bd6ff7773507bcb0bab41417fe2"
2455+ url: "https://pub.dev"
2456+ source: hosted
2457+ version: "0.1.2"
2458+ cli_completion:
2459+ dependency: "direct main"
2460+ description:
2461+ name: cli_completion
2462+ sha256: "1e87700c029c77041d836e57f9016b5c90d353151c43c2ca0c36deaadc05aa3a"
2463+ url: "https://pub.dev"
2464+ source: hosted
2465+ version: "0.4.0"
2466+ yaml:
2467+ dependency: "direct main"
2468+ description:
2469+ name: yaml
2470+ sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
2471+ url: "https://pub.dev"
2472+ source: hosted
2473+ version: "3.1.2"
2474+ sdks:
2475+ dart: ">=3.10.0 <4.0.0"
2476+
2477+ ''' ;
0 commit comments