<commit_before>﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Xml.Linq;

using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;

using CodeJam.Collections;
using CodeJam.PerfTests.Running.Core;
using CodeJam.PerfTests.Running.Messages;
using CodeJam.PerfTests.Running.SourceAnnotations;

using static CodeJam.PerfTests.Loggers.HostLogger;

namespace CodeJam.PerfTests.Analysers
{
	/// <summary>Competition analyser that updates source annotations if competition limit checking failed.</summary>
	/// <seealso cref="CompetitionAnalyser"/>
	[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
	[SuppressMessage("ReSharper", "SuggestVarOrType_BuiltInTypes")]
	[SuppressMessage("ReSharper", "ConvertClosureToMethodGroup")]
	internal class CompetitionAnnotateAnalyser : CompetitionAnalyser
	{
		#region Cached XML annotations from log
		// DONTTOUCH: Each run should use results from previous run log.
		// DO NOT cache log output in static field 
		// as test can be runned multiple times in same appdomain.
		private class LoggedXmlAnnotations : Dictionary<string, XDocument[]> { }

		private static readonly RunState<LoggedXmlAnnotations> _annotationsSlot =
			new RunState<LoggedXmlAnnotations>();
		#endregion

		#region Properties
		/// <summary>
		/// URI of the log that contains competition limits from previous run(s).
		/// Relative paths, file paths and web URLs are supported.
		/// Enable the <see cref="CompetitionAnalyser.LogCompetitionLimits"/> to log the limits.
		/// </summary>
		/// <value>The URI of the log that contains competition limits from previous run(s).</value>
		public string PreviousRunLogUri { get; set; }

		/// <summary>
		/// Count of runs skipped before annotation performed.
		/// Set this to non-zero positive value to skip some runs before first annotation applied.
		/// Should be used together with <see cref="CompetitionAnalyser.MaxRerunsIfValidationFailed"/>
		/// when run on unstable environments such as virtual machines or low-end notebooks.
		/// </summary>
		/// <value>The count of runs performed before updating the limits annotations.</value>
		public int SkipAnnotationsUntilRun { get; set; }

		/// <summary>
		/// Count of additional runs performed after updating source annotations.
		/// Set this to non-zero positive value to proof that the benchmark fits into updated limits.
		/// </summary>
		/// <value>The count of additional runs performed after updating the limits annotations.</value>
		public int AdditionalRerunsIfAnnotationsUpdated { get; set; }
		#endregion

		#region Parsing competition target info
		/// <summary>
		/// Refills the competition targets collection and fills competition limits from the <see cref="PreviousRunLogUri"/>.
		/// </summary>
		/// <param name="competitionTargets">The collection to be filled with competition targets.</param>
		/// <param name="summary">Summary for the run.</param>
		/// <param name="competitionState">State of the run.</param>
		protected override void FillCompetitionTargets(
			CompetitionTargets competitionTargets, Summary summary, CompetitionState competitionState)
		{
			base.FillCompetitionTargets(competitionTargets, summary, competitionState);

			if (string.IsNullOrEmpty(PreviousRunLogUri) || IgnoreExistingAnnotations)
				return;

			var xmlAnnotationDocs = ReadXmlAnnotationDocsFromLog(summary, competitionState);
			if (xmlAnnotationDocs.Length == 0)
			{
				competitionState.WriteMessage(
					MessageSource.Analyser, MessageSeverity.Warning,
					$"No XML annotation documents in the log {PreviousRunLogUri}.");

				return;
			}

			// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
			if (TryFillCompetitionTargetsFromLog(competitionTargets, xmlAnnotationDocs, competitionState))
			{
				competitionState.WriteMessage(
					MessageSource.Analyser, MessageSeverity.Informational,
					$"Competition limits were updated from log file {PreviousRunLogUri}.");
			}
			else<commit_msg>Fix tests<commit_after>﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Xml.Linq;

using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;

using CodeJam.Collections;
using CodeJam.PerfTests.Running.Core;
using CodeJam.PerfTests.Running.Messages;
using CodeJam.PerfTests.Running.SourceAnnotations;

using static CodeJam.PerfTests.Loggers.HostLogger;

namespace CodeJam.PerfTests.Analysers
{
	/// <summary>Competition analyser that updates source annotations if competition limit checking failed.</summary>
	/// <seealso cref="CompetitionAnalyser"/>
	[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
	[SuppressMessage("ReSharper", "SuggestVarOrType_BuiltInTypes")]
	[SuppressMessage("ReSharper", "ConvertClosureToMethodGroup")]
	internal class CompetitionAnnotateAnalyser : CompetitionAnalyser
	{
		#region Cached XML annotations from log
		// DONTTOUCH: Each run should use results from previous run log.
		// DO NOT cache log output in static field 
		// as test can be runned multiple times in same appdomain.
		private class LoggedXmlAnnotations : Dictionary<string, XDocument[]> { }

		private static readonly RunState<LoggedXmlAnnotations> _annotationsSlot =
			new RunState<LoggedXmlAnnotations>();
		#endregion

		#region Properties
		/// <summary>
		/// URI of the log that contains competition limits from previous run(s).
		/// Relative paths, file paths and web URLs are supported.
		/// Enable the <see cref="CompetitionAnalyser.LogCompetitionLimits"/> to log the limits.
		/// </summary>
		/// <value>The URI of the log that contains competition limits from previous run(s).</value>
		public string PreviousRunLogUri { get; set; }

		/// <summary>
		/// Count of runs skipped before annotation performed.
		/// Set this to non-zero positive value to skip some runs before first annotation applied.
		/// Should be used together with <see cref="CompetitionAnalyser.MaxRerunsIfValidationFailed"/>
		/// when run on unstable environments such as virtual machines or low-end notebooks.
		/// </summary>
		/// <value>The count of runs performed before updating the limits annotations.</value>
		public int SkipAnnotationsUntilRun { get; set; }

		/// <summary>
		/// Count of additional runs performed after updating source annotations.
		/// Set this to non-zero positive value to proof that the benchmark fits into updated limits.
		/// </summary>
		/// <value>The count of additional runs performed after updating the limits annotations.</value>
		public int AdditionalRerunsIfAnnotationsUpdated { get; set; }
		#endregion

		#region Parsing competition target info
		/// <summary>
		/// Refills the competition targets collection and fills competition limits from the <see cref="PreviousRunLogUri"/>.
		/// </summary>
		/// <param name="competitionTargets">The collection to be filled with competition targets.</param>
		/// <param name="summary">Summary for the run.</param>
		/// <param name="competitionState">State of the run.</param>
		protected override void FillCompetitionTargets(
			CompetitionTargets competitionTargets, Summary summary, CompetitionState competitionState)
		{
			base.FillCompetitionTargets(competitionTargets, summary, competitionState);

			if (string.IsNullOrEmpty(PreviousRunLogUri))
				return;

			var xmlAnnotationDocs = ReadXmlAnnotationDocsFromLog(summary, competitionState);
			if (xmlAnnotationDocs.Length == 0)
			{
				competitionState.WriteMessage(
					MessageSource.Analyser, MessageSeverity.Warning,
					$"No XML annotation documents in the log {PreviousRunLogUri}.");

				return;
			}

			// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
			if (TryFillCompetitionTargetsFromLog(competitionTargets, xmlAnnotationDocs, competitionState))
			{
				competitionState.WriteMessage(
					MessageSource.Analyser, MessageSeverity.Informational,
					$"Competition limits were updated from log file {PreviousRunLogUri}.");
			}
			else
{'fraction_non_alphanumeric': 0.09268113276940051, 'fraction_numerical': 0.000245188181929631, 'mean_word_length': 4.580027359781122, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2498454', 'n_tokens_mistral': 2428, 'n_tokens_neox': 2169, 'n_words': 689}