NUnit ITestEventListener get output only continuously - c#

I have a very simple TestEventListener that send output to the console and to a text file. However, it currently prints everything and I only want to capture the event, but I'm not sure how to do it. Also, is it possible to get it as it happened? As of right now it only seems to be printing after the test is run which isn't really ideal. Here's what I have now:
class TestListener : ITestEventListener
{
StreamWriter _outputStream;
string _outputFile;
public TestListener(string outputPath)
{
_outputFile = outputPath + "\\ConsoleLog.txt";
_outputStream = new StreamWriter(_outputFile);
}
public void OnTestEvent (string report)
{
WriteText(report);
}
public void WriteText(string text)
{
Console.WriteLine(text);
_outputStream.WriteLine(text);
}
}

It's your code that's printing everything. The report, as you have seen, is XML. It's up to you to look at it in your code and decide what to print.
Most likely, in the events you receive, you will see test starts, test results and immediate text output if you have any. Which of those do you want to display?
As far as only getting output after the test finishes, that would be the test result output, which obviously has to come after the end of the test. It includes an element output with any text writes that were done in the course of the test.
If you want immediate output, which comes as a test-output report, you have to create it in your tests. The only output that is sent this way is Console.Error, TestContext.Error and TestContext.Progress. This is the only output that comes to you before the end of the test.

Related

C# How to capture input from pipeline from continuous stream source

I have a service that runs as a console app and outputs to stdout and stderr streams to the console. The developers don't want to add any logging capabilities since it was mainly designed for linux world and they have tools like logroate and other means already but don't care about the windows port. I want to redirect those streams into a log and I'm able to do it like this:
service.exe 2>&1 >> service.log
But if I leave this running this log will grow out of control. So I tried using something called logrotateWin but it needs to rename the log file and I get access denied since its in use. So I'm trying to write another app that can write to logfile and rotate it based once a day and only keep last n logs.
I want to be able to run it like:
service.exe 2>&1 | logrotater.exe
So I'm trying to write logrotater with the following code but it seems to fail to read the stream from the pipeline. It can read the stream if it stops like from a simple echo "test" command source, but not from service.exe that continuously keeps streaming data out. Any suggestions?
So this works:
echo "test" | logrotater.exe
But this doesn't work:
service.exe 2>&1 | logrotater.exe
static void Main(string[] args) {
Console.SetIn(new StreamReader(Console.OpenStandardInput(8192))); // This will allow input >256 chars
while (Console.In.Peek() != -1) {
string input = Console.In.ReadLine();
Console.WriteLine("Data read was " + input);
}
}
Add a Log() method that opens and closes the file as needed. Moving to a separate method will make it easier to isolate these changes from the rest of the program. One easy way to open/close as needed is with File.AppendAllText().
static void Main(string[] args)
{
Console.SetIn(new StreamReader(Console.OpenStandardInput(8192))); // This will allow input >256 chars
string input;
while ( (input= Console.ReadLine()) != null)
{
Log(input);
}
}
static void Log(string data)
{
string msg = $"Data read was {data}";
Console.WriteLine(msg);
File.AppendAllText("C:\YourPath", msg);
}

How to use FindWindow when we programmatically get the name of the application

I'm quite a newbie and maybe I don't use method correctly at all.
I want to start different acquisitions software at the same time.
For that I have a foreground application window, which simulates a spacebar tap or simulate a Mouseclick when pressing a "play button". I then minimize it, and bring another application into the foreground and do the same. It's actually very fast and works great.
But I have an issue with one piece of software. Its name changes a lot (it takes the name of the folder into, that the video is saved.
To find the name of this application at the time, I use enumwindow and get it with a filter.
But here's my issue the name of the application is saved as a string.
With the foreground application, I have to find it with FindWindow and i have to put into quote marks the name of the application. Of course if I put my string into quote marks it doesn't work.
Here's my code:
//[Lot of Dllimport]
public void namewindow()
{
string[] strWindowsTitles = GetDesktopWindowsTitles();
//all the name of open applications
foreach (string strTitle in strWindowsTitles)
{
if (strTitle.Contains("Motive"))
{
string Motive = strTitle;
//Here if I put a MessageBox.Show(Motive),
//I have a name like:
//Motive:Body 1.10.0 Beta 1 (C:\Users\Public\Documents\OptiTrack\
}
}
}
public void openwindow()
{
IntPtr splashwindow = FindWindowByCaption(IntPtr.Zero, "Motive");
FindWindow;
SetForegroundWindow(splashwindow);
ShowWindowAsync(splashwindow, SW_SHOWNORMAL);
}
This work perfectly fine with
IntPtr splashwindow = FindWindowByCaption(IntPtr.Zero, "Kinovea");
FindWindow;
SetForegroundWindow(splashwindow);
ShowWindowAsync(splashwindow, SW_SHOWNORMAL);
for example.
So it works fine if I put the name of the application between the quotes, but if I put my string between the quotes, nothing happens. Have you get any idea how to solve this issue?
Going on what you also posted in this question, I feel your code should be this instead:
public string nameWindow(string searchFor)
{
string[] strWindowsTitles = GetDesktopWindowsTitles();
//all the names of open applications
foreach (string strTitle in strWindowsTitles)
{
if (strTitle.Contains(searchFor))
{
return strTitle;
}
}
else
return null;
}
public void openwindow()
{
string motiveWindow = nameWindow("Motive");
if (motiveWindow != null){
IntPtr splashwindow = FindWindowByCaption(IntPtr.Zero, motiveWindow);
//FindWindow;//Not sure what this does?
SetForegroundWindow(splashwindow);
ShowWindowAsync(splashwindow, SW_SHOWNORMAL);
}
}
That changes it so your method of nameWindow() will locate a window (The first one it comes across) with the word you have passed, to the method, in the variable of searchFor. In this case, "Motive". Then, if the variable motiveWindow is not null (So a window has been found), it will run your expected code and display the window.
You need to be careful about how you set the variables and what returns what. At the moment your nameWindow() doesn't seem to be doing much, possibly setting a variable called 'Motive', which I've not seen declared, but you then never use that variable elsewhere. Here, we're returning a variable and acting upon the data returned. You may find you want to make your openWindow() method take a variable, attempt to open a window of the same name, if none is found, then it calls the method nameWindow() and searches for it. That way you can work with both scenarios you have presented.

Write into a log file with C#

I am using the JitBit Macro Recorder to create "bots" that save me a lot of time at work. This program can use the mouse and the keyboard and perform tasks by checking different if-options like "if image found on screen".
My newest "bot" is about 900 lines of commands long and I would like to make a log-file to find an error somewhere in there. Sadly, this program doesn't offer such an option, but it let's me use c# as a task. I have NO experience with c# but I thought, that this is easy to do for someone who has some experience.
If I click execute c# code, I get the following input field:
Important: This code MUST contain a class named "Program" with a static method "Main"!
public class Program
{
public static void Main()
{
System.Windows.Forms.MessageBox.Show("test");
}
}
Now I need two code templates:
1. Write a message to a "bot_log.txt" located on my desktop.
[19.05.2016 - 12:21:09] "Checking if item with number 3 exists..."
The number "3" changes with every run and is an exact paste of the clipboard.
2. Add an empty line to the same file
(Everything should be added to a new line at the end of this file.)
If you have no idea how to program in C#, then you should learn it,
if you want to use code provided from answers.
And if you want to generate timestamps and stuff then it's not done within minutes and I don't think someone writes the whole code just for your fitting. Normally questions should have at least a bit of general interest.
Anyway:
This works, if you have a RichTextTbox in your program.
Just do a new event (like clicking a button) and do this inside it.
(This was posted somewhere here too or on another site, with sligh changes)
public static void SaveMyFile(RichTextBox rtb)
{
// Create a SaveFileDialog to request a path and file name to save to.
SaveFileDialog saveLog = new SaveFileDialog();
// Initialize the SaveFileDialog to specify the RTF extention for the file.
saveLog.DefaultExt = "*.rtf";
saveLog.Filter = "RTF Files|*.rtf"; //You can do other extensions here.
// Determine whether the user selected a file name from the saveFileDialog.
if (saveLog.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
saveLog.FileName.Length > 0)
{
// Save the contents of the RichTextBox into the file.
try
{
rtb.SaveFile(saveLog.FileName);
}
catch
{
MessageBox.Show("Error creating the file.\n Is the name correct and is enough free space on your disk\n ?");
}
MessageBox.Show("Logfile was saved successful.");
}
}

Get the console buffer without the last line with C#?

What I'm trying to achieve is a self-compiled c# file without toxic output.I'm trying to achieve this with Console.MoveBufferArea method but looks does not work.
Eg. - save the code below with .bat extension :
// 2>nul||#goto :batch
/*
:batch
#echo off
setlocal
:: find csc.exe
set "frm=%SystemRoot%\Microsoft.NET\Framework\"
for /f "tokens=* delims=" %%v in ('dir /b /a:d /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*"') do (
set netver=%%v
goto :break_loop
)
:break_loop
set csc=%frm%%netver%\csc.exe
:: csc.exe found
%csc% /nologo /out:"%~n0.exe" "%~dpsfnx0"
%~n0.exe
endlocal
exit /b 0
*/
public class Hello
{
public static void Main() {
ClearC();
System.Console.WriteLine("Hello, C# World!");
}
private static void ClearC() {
System.Console.MoveBufferArea(
0,0,
System.Console.BufferWidth,System.Console.BufferHeight-1,
0,0
);
}
}
the output will be:
C:\>// 2>nul ||
Hello, C# World!
What want is to rid of the // 2>nul || .Is it possible? Is there something wrong in my logic (the ClearC method)?Do I need PInvoke?
If you want to do it in the C#, then changing your ClearC function to the following seems to work:
public static void ClearC() {
System.Console.CursorTop = System.Console.CursorTop - 1;
System.Console.Write(new string(' ', System.Console.BufferWidth));
System.Console.CursorTop = System.Console.CursorTop - 1;
}
Essentially, move the Cursor up a line (to the line that should contain your prompt), blank the entire line, then move up another line (which should move you to the blank line between commands). Future output will then take place from here.
The obvious downside to this is that you need to wait for the C# code to be compiled and executed, before the // 2>nul || is removed. If you want it to be faster, you'll need to find a console/batch file based solution. The other thing to keep in mind is that is assumes that the prompt is a single line. If it's a really long prompt that spans two lines, then you'll get a bit of a mess, so it may be better to clear two lines, depending on how you're planning on using this.
If you want to go the whole hog and start reading the console buffer to determine how long the prompt is, then you might want to have a look at this question. Whilst the article link in the answer is broken, the code download still seems to work.
If you want to go down the batchfile based approach, then you might want to have a look at this question.

VS2008: File creation fails randomly in unit testing?

I'm working on implementing a reasonably simple XML serializer/deserializer (log file parser) application in C# .NET with VS 2008. I have about 50 unit tests right now for various parts of the code (mostly for the various serialization operations), and some of them seem to be failing mostly at random when they deal with file I/O.
The way the tests are structured is that in the test setup method, I create a new empty file at a certain predetermined location, and close the stream I get back. Then I run some basic tests on the file (varying by what exactly is under test). In the cleanup method, I delete the file again.
A large portion (usually 30 or more, though the number varies run to run) of my unit tests will fail at the initialize method, claiming they can't access the file I'm trying to create. I can't pin down the exact reason, since a test that will work one run fails the next; they all succeed when run individually.
What's the problem here? Why can't I access this file across multiple unit tests?
Relevant methods for a unit test that will fail some of the time:
[TestInitialize()]
public void LogFileTestInitialize()
{
this.testFolder =
System.Environment.GetFolderPath(
System.Environment.SpecialFolder.LocalApplicationData
);
this.testPath = this.testFolder + "\\empty.lfp";
System.IO.File.Create(this.testPath).Close();
}
[TestMethod()]
public void LogFileConstructorTest()
{
string filePath = this.testPath;
LogFile target = new LogFile(filePath);
Assert.AreNotEqual(null, target);
Assert.AreEqual(this.testPath, target.filePath);
Assert.AreEqual("empty.lfp", target.fileName);
Assert.AreEqual(this.testFolder + "\\empty.lfp.lfpdat", target.metaPath);
}
[TestCleanup()]
public void LogFileTestCleanup()
{
System.IO.File.Delete(this.testPath);
}
And the LogFile() constructor:
public LogFile(String filePath)
{
this.entries = new List<Entry>();
this.filePath = filePath;
this.metaPath = filePath + ".lfpdat";
this.fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
}
The precise error message:
Initialization method
LogFileParserTester.LogFileTest.LogFileTestInitialize
threw exception.
System.IO.IOException:
System.IO.IOException: The process
cannot access the file
'C:\Users\<user>\AppData\Local\empty.lfp'
because it is being used by another
process..
You should be mocking the file system access, and not actually reading/writing files in your unit tests.
Sounds like some of the tests are being run at the same time. Do the individual tests write to the file, or just read it? If they're read only, I'm sure we can make a minor change to enable them to run concurrently. More details?

Categories