Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions documentation/general/dotnet-run-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ and working directory is not changed (e.g., `cd /x/ && dotnet run /y/file.cs` ru
If a dash (`-`) is given instead of the target path (i.e., `dotnet run -`), the C# file to be executed is read from the standard input.
In this case, the current working directory is not used to search for other files (launch profiles, other sources in case of multi-file apps);
the compilation consists solely of the single file read from the standard input.
However, the current working directory is still used as the working directory for building and executing the program.
To reference projects relative to the current working directory (instead of relative to the temporary directory the file is isolated in),
you can use something like `#:project $(MSBuildStartupDirectory)/relative/path`.

`dotnet path.cs` is a shortcut for `dotnet run --file path.cs` provided that `path.cs` is a valid [target path](#target-path) (`dotnet -` is currently not supported)
and it is not a DLL path, built-in command, or a NuGet tool (e.g., `dotnet watch` invokes the `dotnet-watch` tool
Expand Down
101 changes: 100 additions & 1 deletion test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -468,19 +468,118 @@ public void Precedence_NuGetTool()
[Fact]
public void ReadFromStdin()
{
var testInstance = _testAssetsManager.CreateTestDirectory();
new DotnetCommand(Log, "run", "-")
.WithWorkingDirectory(testInstance.Path)
.WithStandardInput("""
Console.WriteLine("Hello from stdin");
Console.WriteLine("Read: " + (Console.ReadLine() ?? "null"));
Console.WriteLine("Working directory: " + Environment.CurrentDirectory);
""")
.Execute()
.Should().Pass()
.And.HaveStdOut("""
.And.HaveStdOut($"""
Hello from stdin
Read: null
Working directory: {testInstance.Path}
""");
}

/// <summary>
/// <c>Directory.Build.props</c> doesn't have any effect on <c>dotnet run -</c>.
/// </summary>
[Fact]
public void ReadFromStdin_BuildProps()
{
var testInstance = _testAssetsManager.CreateTestDirectory();

File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """
<Project>
<PropertyGroup>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
</Project>
""");

new DotnetCommand(Log, "run", "-")
.WithWorkingDirectory(testInstance.Path)
.WithStandardInput("""
Console.WriteLine("Hello from stdin");
""")
.Execute()
.Should().Pass()
.And.HaveStdOut("Hello from stdin");

new DotnetCommand(Log, "run", "-")
.WithWorkingDirectory(testInstance.Path)
.WithStandardInput("""
#:property ImplicitUsings=disable
Console.WriteLine("Hello from stdin");
""")
.Execute()
.Should().Fail()
// error CS0103: The name 'Console' does not exist in the current context
.And.HaveStdOutContaining("error CS0103");
}

/// <summary>
/// <c>Directory.Build.props</c> doesn't have any effect on <c>dotnet run -</c>.
/// </summary>
[Fact]
public void ReadFromStdin_ProjectReference()
{
var testInstance = _testAssetsManager.CreateTestDirectory();

var libDir = Path.Join(testInstance.Path, "lib");
Directory.CreateDirectory(libDir);

File.WriteAllText(Path.Join(libDir, "Lib.csproj"), $"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework>
</PropertyGroup>
</Project>
""");

File.WriteAllText(Path.Join(libDir, "Lib.cs"), """
namespace Lib;
public class LibClass
{
public static string GetMessage() => "Hello from Lib";
}
""");

var appDir = Path.Join(testInstance.Path, "app");
Directory.CreateDirectory(appDir);

new DotnetCommand(Log, "run", "-")
.WithWorkingDirectory(appDir)
.WithStandardInput($"""
#:project $(MSBuildStartupDirectory)/../lib
Console.WriteLine(Lib.LibClass.GetMessage());
""")
.Execute()
.Should().Pass()
.And.HaveStdOut("Hello from Lib");

// Relative paths are resolved from the isolated temp directory, hence they don't work.

var errorParts = DirectiveError("app.cs", 1, FileBasedProgramsResources.InvalidProjectDirective,
string.Format(FileBasedProgramsResources.CouldNotFindProjectOrDirectory, "{}")).Split("{}");
errorParts.Should().HaveCount(2);

new DotnetCommand(Log, "run", "-")
.WithWorkingDirectory(appDir)
.WithStandardInput($"""
#:project ../lib
Console.WriteLine(Lib.LibClass.GetMessage());
""")
.Execute()
.Should().Fail()
.And.HaveStdErrContaining(errorParts[0])
.And.HaveStdErrContaining(errorParts[1]);
}

[Fact]
public void ReadFromStdin_NoBuild()
{
Expand Down
Loading