How to add attachments to Allure report in C#? - c#

The Allure framework is a really beautiful framework for test reporting.
Yet it has rather bad documentation for C#.
I want to add some things to my allure report:
Debug log (like all things I write to debug)
Screenshot
A file
How to do it? I have no idea, please help me if you know how to do it. It seems like AllureLifecycle class can help me but I'm not sure how to use it.
In case it matters I use Allure together with SpecFlow and MS test.

I searched more and seems I found the Truth.
And the Truth is it's possible to add all attachments I wanted but they can be added only as a file:
byte[] log = Encoding.ASCII.GetBytes(Log.GetAllLog());
AllureLifecycle.Instance.AddAttachment("DebugLog", "application/json", log, "json");
If you want to add a file from actually a path (location) you can do it with the same method but a different overload.
So just place this code in a "teardown\afterscenario" method or at any other place (for example at "afterstep" method) where you want to make this attachment. I use SpecFlow so if I add this to "AfterStep" hook then Allure displays those files attached to a specific step! That's amazing!)

it seems that allure has some events that can be used.
See : https://github.com/allure-framework/allure-csharp-commons/blob/master/AllureCSharpCommons.Tests/IntegrationTests.cs for more information.
haven't tried it myself, but something like this should work according to the documentation.
_lifecycle = Allure.DefaultLifecycle;
_lifecycle.Fire(new
MakeAttachmentEvent(AllureResultsUtils.TakeScreenShot(),
"Screenshot",
"image/png"));
_lifecycle.Fire(new MakeAttachmentEvent(File.ReadAllBytes("TestData/attachment.json"),
"JsonAttachment",
"application/json"));
Hope this helps.

Using this kind of code in AfterScenario method:
if (_scenarioContext.TestError != null)
{
var path = WebElementsUtils.MakeScreenshot(_driver);
_allureLifecycle.AddAttachment(path);
}
First it verifies, if Scenario passed, if not then
WebElementsUtils.MakeScreenshot(_driver)
method makes screenshot and returns it's path. Then this path I giving to Allure. As a second parameter in the same method I can give a name of the screenshot. As a result I am getting a screenshot in AfterScenario block in Allure report.
P.S. This is only for screenshots, about logs can't tell nothing.

With this example you can add an attachment exactly to the failed step
[AfterStep(Order = 0)]
public void RecordScreenFailure(ScenarioContext scenarioContext)
{
if (scenarioContext.TestError != null)
{
Allure.Commons.AllureLifecycle allureInstance = Allure.Commons.AllureLifecycle.Instance;
string screenshotPath = MagicMethodMakingScreenshotAndReturningPathToIt();
allureInstance.UpdateTestCase(testResult => {
Allure.Commons.StepResult failedStepRsult =
testResult.steps.First(step => step.status == Allure.Commons.Status.failed);
failedStepRsult.attachments.Add(new Allure.Commons.Attachment() {
name = "failure screen",
source = screenshotPath,
type = "image/png"
});
});
}
}

Related

"Value does not exist" (WW CadLib)

I think this is a rather straightforward issue, but I don't have much information to go on. I have this code to try and read a DWG file into memory, so that I can read and manipulate the data. I am getting an error that the parameter "Value" cannot be null.
While that does let me know something is wrong, how do I proceed in figuring out what exactly this value is so that I can fix it?
string basePath = Path.Combine($"{Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)}", "temp");
string fileName = Path.Combine(basePath, "ATemplateV0.2.dwg");
if(File.Exists(fileName))
{
DwgReader dwgReader = new(fileName);
try
{
DxfModel dxfModel = dwgReader.Read();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
WW CadLib needs a license to run, if you don't have one that may be causing the error.
The code example in the answer from #b166er is referring to an Open Source library called ACadSharp to read dwg/dxf files from one of my repositories.
Right now you can use a pre-release version of it in Nuget
You can pass a onNotification event into the DwgReader constructor that might give you more information. Examples here: https://github.com/DomCR/ACadSharp/blob/master/ACadSharp.Examples/Program.cs

Null Reference Exception when calling iText7 PdfAcroForm.GetAcroForm() in .Net Core 3.1 class library

I am working on converting an application to .Net Core 3.1, and in my class library I am generating a PDF form from an existing template, and filling that form with data. In ITextSharp, the predecessor to IText7, the PdfAcroForm static method ".GetAcroForm()" worked perfectly, but in the current version of iText7 (7.1.12) a Null Reference Exception is thrown. I have followed the documentation to the best of my ability, but I am unsure how to continue. Any suggestions would be appreciated.
NOTE: The template path exists, the new document shows that it has been filled properly, and it is impossible to "new" a PdfAcroForm, you are required to use the static .GetAcroForm() method.
A null check will not solve this issue, as the object should never be null. The documentation indicates that the .GetAcroForm() method will create a new form if the parameter "createNotExist" is set to true, which I have done here.
I have researched and have located an issue on the iText GitHub that indicates that this issue was "fixed" around a year ago: https://github.com/itext/itext7/pull/44#issue-351612749
The following is the method which prepares the forms:
public string DocumentGenerator(string templatePath, FormFieldSet[] formFieldSet, bool useSpecailOutputPath)
{
if(!File.Exists(templatePath))
{
throw new Exception("The template file provided does not exist: MC-071(iText)");
}
string newFile = useSpecailOutputPath ?
m_SpecialOutputPath :
Path.GetTempPath() + Guid.NewGuid().ToString() + ".pdf";
try
{
PdfDocument newDocument = new PdfDocument(new PdfReader(templatePath), new PdfWriter(newFile));
PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(newDocument, true); // <=== Exception Thrown Here
foreach (FormFieldSet fs in formFieldSet)
{
acroForm.GetField(fs.FieldName).SetValue(fs.FillValue);
}
// Sets form flattening
acroForm.FlattenFields();
// Closes and writes the form
newDocument.Close();
return newFile;
}
catch { return string.Empty; };
}
Any suggestions would be greatly appreciated
I had the same problem, and after digging down all the way to iText7's internal objects and methods, I finally "solved" my problem.
Apparently iText has some internal errors/exceptions that they are just sort of "skipping" and "pushing past", because I realized by accident that I had "Enable Just My Code" in Visual Studios disabled, and so my system was trying to debug iText7's code as well as mine. The moment that I re-enabled it in my Visual Studio settings (Tools > Options > Debugging > General > Enable Just My Code checkbox), the problem magically went away.
So I spent four hours trying to troubleshoot a problem that was in THEIR code, but that they apparently found some way to work around and push through the method anyways even on a null reference failure.
My convert to PDF function is now working just fine.
Just an update to anyone looking for this issue. This is a known issue and is fixed in the current development branch. You are safe to bypass the exception in visual studio until it is corrected. This has no negative impact on the functionality and is the result of a misplaced return in the original iText7 source.

How do you actually implement the Search Contract? (C#)

I'm having some trouble understanding and getting the search contract to work in my Store app. I have been unable to find any sort of documentation or guide that explains the structure of using the contract. (I've looked at the quickstarts on MSDN, the Search Contract sample and the build video, but that only really deals with javascript)
So far I've been able to run a query and get a list (of Custom Objects) into my search contract page, and from there I try to assign that to defaultviewmodel.results, but no matter what query I type nothing shows up I on the page. Is there something else I need to set?
What I have so far is as follows (excerpts):
App.xaml.cs
protected override void OnSearchActivated(Windows.ApplicationModel.Activation.SearchActivatedEventArgs args)
{
SearchCharmResultsPage.Activate(args.QueryText, args.PreviousExecutionState);
SearchCharmResultsPage.ProcessSearchQuery(args.QueryText);
}
public async static void ProcessSearchQuery(string queryString)
{
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("recipeCustomObject Debug.WriteLine("Database exists, connecting");
SQLiteAsyncConnection connection = new SQLiteAsyncConnection("CustomObject_db");
List<CustomObject> resultsList = new List<CustomObject>();
string query = "SELECT * FROM CustomObjectDB";
resultsList = await connection.QueryAsync<RecipeRecord>(query);
}
catch (FileNotFoundException fnfExc)
{
Debug.WriteLine("FNFEXC: " + fnfExc.ToString());
}
}
I think it is possible that here lies the problem, though I'm not sure if it is, or how to change it.
the resultsList list is created here, but because the method it asynchronous, I can't return from the method. Because of this I'm guess that when I try to assign this.DefaultViewModel[Results] = resultsList; in the LoadStateMethod, the object doesn't exist (thought the program throws no error). When I try to add the same line in the ProcessSearchQuery method, i'm told that this is not valid in a static method, but I think I need the method to be static? My problem might just be a fundamental logic error?
Finally got it! found the solution here: http://jeffblankenburg.com/2012/11/06/31-days-of-windows-8-day-6-search-contract
For those looking for an answer in the future, the key is to make sure you have your search logic within the Filter_SelectionChanged method, which was something I wasn't doing. Look at the guide within the above link to get an idea of the structure.
Have you looked at the Search contract sample on the developer center? There's a C#/XAML version there as well.
My open source Win8 RSS Reader framework implements Search (and Share) have a look at the source and if you still got questions, I'll be happy to help http://win8rssreader.codeplex.com/

C# code completion with NRefactory 5

I just found out about NRefactory 5 and I would guess, that it is the most suitable solution for my current problem. At the moment I'm developing a little C# scripting application for which I would like to provide code completion. Until recently I've done this using the "Roslyn" project from Microsoft. But as the latest update of this project requires .Net Framework 4.5 I can't use this any more as I would like the app to run under Win XP as well. So I have to switch to another technology here.
My problem is not the compilation stuff. This can be done, with some more effort, by .Net CodeDomProvider as well. The problem ist the code completion stuff. As far as I know, NRefactory 5 provides everything that is required to provide code completion (parser, type system etc.) but I just can't figure out how to use it. I took a look at SharpDevelop source code but they don't use NRefactory 5 for code completion there, they only use it as decompiler. As I couldn't find an example on how to use it for code completion in the net as well I thought that I might find some help here.
The situation is as follows. I have one single file containing the script code. Actually it is not even a file but a string which I get from the editor control (by the way: I'm using AvalonEdit for this. Great editor!) and some assemblies that needs to get referenced. So, no solution files, no project files etc. just one string of source code and the assemblies.
I've taken a look at the Demo that comes with NRefactory 5 and the article on code project and got up with something like this:
var unresolvedTypeSystem = syntaxTree.ToTypeSystem();
IProjectContent pc = new CSharpProjectContent();
// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(unresolvedTypeSystem);
// Add referenced assemblies:
pc = pc.AddAssemblyReferences(new CecilLoader().LoadAssemblyFile(
System.Reflection.Assembly.GetAssembly(typeof(Object)).Location));
My problem is that I have no clue on how to go on. I'm not even sure if it is the right approach to accomplish my goal. How to use the CSharpCompletionEngine? What else is required? etc. You see there are many things that are very unclear at the moment and I hope you can bring some light into this.
Thank you all very much in advance!
I've just compiled and example project that does C# code completion with AvalonEdit and NRefactory.
It can be found on Github here.
Take a look at method ICSharpCode.NRefactory.CSharp.CodeCompletion.CreateEngine. You need to create an instance of CSharpCompletionEngine and pass in the correct document and the resolvers. I managed to get it working for CTRL+Space compltition scenario. However I am having troubles with references to types that are in other namespaces. It looks like CSharpTypeResolveContext does not take into account the using namespace statements - If I resolve the references with CSharpAstResolver, they are resolved OK, but I am unable to correctly use this resolver in code completition scenario...
UPDATE #1:
I've just managed to get the working by obtaining resolver from unresolved fail.
Here is the snippet:
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var resolver3 = unresolvedFile.GetResolver(cmp, loc); // get the resolver from unresolvedFile
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
Update #2:
Here is the complete method. It references classes from unit test projects, sou you would need to reference/copy them into your project:
public static IEnumerable<ICompletionData> DoCodeComplete(string editorText, int offset) // not the best way to put in the whole string every time
{
var doc = new ReadOnlyDocument(editorText);
var location = doc.GetLocation(offset);
string parsedText = editorText; // TODO: Why there are different values in test cases?
var syntaxTree = new CSharpParser().Parse(parsedText, "program.cs");
syntaxTree.Freeze();
var unresolvedFile = syntaxTree.ToTypeSystem();
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
IProjectContent pctx = new CSharpProjectContent();
var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value};
pctx = pctx.AddAssemblyReferences(refs);
pctx = pctx.AddOrUpdateFiles(unresolvedFile);
var cmp = pctx.CreateCompilation();
var resolver3 = unresolvedFile.GetResolver(cmp, location);
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();
var data = engine.GetCompletionData(offset, controlSpace: false);
return data;
}
}
Hope it helps,
Matra
NRefactory 5 is being used in SharpDevelop 5. The source code for SharpDevelop 5 is currently available in the newNR branch on github. I would take a look at the CSharpCompletionBinding class which has code to display a completion list window using information from NRefactory's CSharpCompletionEngine.

Visual Studio Custom Language Service

I am attempting to implement a Language Service in a VSPackage using the MPF, and it's not working quite as I understand it should.
I have several implementations already, such as ParseSource parsing the input file with a ParseRequest. However, when it finds an error, it adds it with AuthoringSink.AddError. The documentation for this implies it adds it to the Error List for me; it doesn't.
I also have a simple MySource class, a subclass of Source. I return this new class with an overridden LanguageService.CreateSource method. The documentation for OnCommand says it's fired 'when a command is entered'. However, it's not.
There's obviously some intermediate step which I haven't done correctly. I've already rambled enough, so I'll be glad to give any additional details by request.
Any clarification is much appreciated.
For the AuthoringSink error list question, I use this behavior in my Language Service. In ParseSource, the ParseRequest class has an AuthoringSink. You can also create a new ErrorListProvider if you want to work outside of the parser's behavior. Here is some example code:
error_list = new ErrorListProvider(this.Site);
error_list.ProviderName = "MyLanguageService Errors";
error_list.ProviderGuid = new Guid(this.errorlistGUIDstring.);
}
ErrorTask task = new ErrorTask();
task.Document = filename;
task.CanDelete = true;
task.Category = TaskCategory.CodeSense;
task.Column = column;
task.Line = line;
task.Text = message;
task.ErrorCategory = TaskErrorCategory.Error;
task.Navigate += NavigateToParseError;
error_list.Tasks.Add(task);
I hope this was helpful.
OnCommand should be firing every time there is a command, in your MySource class you can do something like this (pulled from working code):
public override void OnCommand(IVsTextView textView, VsCommands2K command, char ch)
{
if (textView == null || this.LanguageService == null
|| !this.LanguageService.Preferences.EnableCodeSense)
return;
if (command == Microsoft.VisualStudio.VSConstants.VSStd2KCmdID.TYPECHAR)
{
if (char.IsLetterOrDigit(ch))
{
//do something cool
}
}
base.OnCommand(textView, command, ch);
}
If that doesn't work double check that CodeSense = true in your ProvideLanguageService attribute when you setup your LanguageService package. A whole lot of what is cool to do in the LanguageService requires these attributes to be correctly turned on. Some even give cool behaviors for free!
Another thing to be careful of is that some behaviors like colorizer don't function correctly in the hive in my experience. I don't think these were ones that gave me trouble, but I implemented these a couple of years ago so I'm mostly just looking back at old code.
AuthoringSink.AddError only adds errors to the error list if ParseRequest.Reason is ParseReason.Check. When your ParseSource function attempts to add errors while parsing for any other ParseReason, nothing will happen.
It's possible that your language service is never calling ParseSource with this ParseReason. As far as I know, the only way to get a ParseReason of Check (outside of manually calling BeginParse or ParseSource yourself) is to proffer your service with an idle timer.

Categories

Resources