@@ -1874,6 +1874,115 @@ final class PackageToolTests: CommandsTestCase {
1874
1874
}
1875
1875
}
1876
1876
1877
+ // Test reporting of plugin diagnostic messages at different verbosity levels
1878
+ func testCommandPluginDiagnostics( ) throws {
1879
+ // Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
1880
+ try XCTSkipIf ( !UserToolchain. default. supportsSwiftConcurrency ( ) , " skipping because test environment doesn't support concurrency " )
1881
+
1882
+ // Match patterns for expected messages
1883
+ let isEmpty = StringPattern . equal ( " " )
1884
+ let isOnlyPrint = StringPattern . equal ( " command plugin: print \n " )
1885
+ let containsRemark = StringPattern . contains ( " command plugin: Diagnostics.remark " )
1886
+ let containsWarning = StringPattern . contains ( " command plugin: Diagnostics.warning " )
1887
+ let containsError = StringPattern . contains ( " command plugin: Diagnostics.error " )
1888
+
1889
+ try fixture ( name: " Miscellaneous/Plugins/CommandPluginDiagnosticsStub " ) { fixturePath in
1890
+ func runPlugin( flags: [ String ] , diagnostics: [ String ] , completion: ( String , String ) -> Void ) throws {
1891
+ let ( stdout, stderr) = try SwiftPM . Package. execute ( flags + [ " print-diagnostics " ] + diagnostics, packagePath: fixturePath)
1892
+ completion ( stdout, stderr)
1893
+ }
1894
+
1895
+ // Diagnostics.error causes SwiftPM to return a non-zero exit code, but we still need to check stdout and stderr
1896
+ func runPluginWithError( flags: [ String ] , diagnostics: [ String ] , completion: ( String , String ) -> Void ) throws {
1897
+ XCTAssertThrowsError ( try SwiftPM . Package. execute ( flags + [ " print-diagnostics " ] + diagnostics, packagePath: fixturePath) ) { error in
1898
+ guard case SwiftPMError . executionFailure( _, let stdout, let stderr) = error else {
1899
+ return XCTFail ( " invalid error \( error) " )
1900
+ }
1901
+ completion ( stdout, stderr)
1902
+ }
1903
+ }
1904
+
1905
+ // Default verbosity
1906
+ // - stdout is always printed
1907
+ // - Diagnostics below 'warning' are suppressed
1908
+
1909
+ try runPlugin ( flags: [ ] , diagnostics: [ " print " ] ) { stdout, stderr in
1910
+ XCTAssertMatch ( stdout, isOnlyPrint)
1911
+ XCTAssertMatch ( stderr, isEmpty)
1912
+ }
1913
+
1914
+ try runPlugin ( flags: [ ] , diagnostics: [ " print " , " remark " ] ) { stdout, stderr in
1915
+ XCTAssertMatch ( stdout, isOnlyPrint)
1916
+ XCTAssertMatch ( stderr, isEmpty)
1917
+ }
1918
+
1919
+ try runPlugin ( flags: [ ] , diagnostics: [ " print " , " remark " , " warning " ] ) { stdout, stderr in
1920
+ XCTAssertMatch ( stdout, isOnlyPrint)
1921
+ XCTAssertMatch ( stderr, containsWarning)
1922
+ }
1923
+
1924
+ try runPluginWithError ( flags: [ ] , diagnostics: [ " print " , " remark " , " warning " , " error " ] ) { stdout, stderr in
1925
+ XCTAssertMatch ( stdout, isOnlyPrint)
1926
+ XCTAssertMatch ( stderr, containsWarning)
1927
+ XCTAssertMatch ( stderr, containsError)
1928
+ }
1929
+
1930
+ // Quiet Mode
1931
+ // - stdout is always printed
1932
+ // - Diagnostics below 'error' are suppressed
1933
+
1934
+ try runPlugin ( flags: [ " -q " ] , diagnostics: [ " print " ] ) { stdout, stderr in
1935
+ XCTAssertMatch ( stdout, isOnlyPrint)
1936
+ XCTAssertMatch ( stderr, isEmpty)
1937
+ }
1938
+
1939
+ try runPlugin ( flags: [ " -q " ] , diagnostics: [ " print " , " remark " ] ) { stdout, stderr in
1940
+ XCTAssertMatch ( stdout, isOnlyPrint)
1941
+ XCTAssertMatch ( stderr, isEmpty)
1942
+ }
1943
+
1944
+ try runPlugin ( flags: [ " -q " ] , diagnostics: [ " print " , " remark " , " warning " ] ) { stdout, stderr in
1945
+ XCTAssertMatch ( stdout, isOnlyPrint)
1946
+ XCTAssertMatch ( stderr, isEmpty)
1947
+ }
1948
+
1949
+ try runPluginWithError ( flags: [ " -q " ] , diagnostics: [ " print " , " remark " , " warning " , " error " ] ) { stdout, stderr in
1950
+ XCTAssertMatch ( stdout, isOnlyPrint)
1951
+ XCTAssertNoMatch ( stderr, containsRemark)
1952
+ XCTAssertNoMatch ( stderr, containsWarning)
1953
+ XCTAssertMatch ( stderr, containsError)
1954
+ }
1955
+
1956
+ // Verbose Mode
1957
+ // - stdout is always printed
1958
+ // - All diagnostics are printed
1959
+ // - Substantial amounts of additional compiler output are also printed
1960
+
1961
+ try runPlugin ( flags: [ " -v " ] , diagnostics: [ " print " ] ) { stdout, stderr in
1962
+ XCTAssertMatch ( stdout, isOnlyPrint)
1963
+ // At this level stderr contains extra compiler output even if the plugin does not print diagnostics
1964
+ }
1965
+
1966
+ try runPlugin ( flags: [ " -v " ] , diagnostics: [ " print " , " remark " ] ) { stdout, stderr in
1967
+ XCTAssertMatch ( stdout, isOnlyPrint)
1968
+ XCTAssertMatch ( stderr, containsRemark)
1969
+ }
1970
+
1971
+ try runPlugin ( flags: [ " -v " ] , diagnostics: [ " print " , " remark " , " warning " ] ) { stdout, stderr in
1972
+ XCTAssertMatch ( stdout, isOnlyPrint)
1973
+ XCTAssertMatch ( stderr, containsRemark)
1974
+ XCTAssertMatch ( stderr, containsWarning)
1975
+ }
1976
+
1977
+ try runPluginWithError ( flags: [ " -v " ] , diagnostics: [ " print " , " remark " , " warning " , " error " ] ) { stdout, stderr in
1978
+ XCTAssertMatch ( stdout, isOnlyPrint)
1979
+ XCTAssertMatch ( stderr, containsRemark)
1980
+ XCTAssertMatch ( stderr, containsWarning)
1981
+ XCTAssertMatch ( stderr, containsError)
1982
+ }
1983
+ }
1984
+ }
1985
+
1877
1986
func testCommandPluginNetworkingPermissions( permissionsManifestFragment: String , permissionError: String , reason: String , remedy: [ String ] ) throws {
1878
1987
// Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
1879
1988
try XCTSkipIf ( !UserToolchain. default. supportsSwiftConcurrency ( ) , " skipping because test environment doesn't support concurrency " )
0 commit comments