<commit_before>﻿using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;

namespace Rocks.Tests.Generators;

public static class NamingGeneratorTests
{
	[Test]
	public static async Task GenerateWhenNamesAreKeywordsAsync()
	{
		var code =
			"""
			using Rocks;
			
			public interface IUseKeyword
			{
			    void Foo(string @namespace, string @event, string @property);   
			}

			public static class Test
			{
				public static void Go()
				{
					var expectations = Rock.Create<IUseKeyword>();
				}<commit_msg>#189 since we're using FQNs now, this issue is already resolved<commit_after>﻿using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;

namespace Rocks.Tests.Generators;

public static class NamingGeneratorTests
{
	[Test]
	public static async Task GenerateWhenNonVirtualMembersAreNeededAsync()
	{
		var code =
			"""
			using Rocks;
			using System;
			using System.IO;

			public class IHaveDelegate
			{
				public Func<Stream, Stream> Processor { get; init; }   
				public virtual void Foo() { }
			}

			public static class Test
			{
				public static void Go()
				{
					var expectations = Rock.Create<IHaveDelegate>();
				}
			}
			""";

		var generatedCode =
			"""
			using Rocks.Extensions;
			using System.Collections.Generic;
			using System.Collections.Immutable;
			#nullable enable
			
			internal static class CreateExpectationsOfIHaveDelegateExtensions
			{
				internal static global::Rocks.Expectations.MethodExpectations<global::IHaveDelegate> Methods(this global::Rocks.Expectations.Expectations<global::IHaveDelegate> @self) =>
					new(@self);
				
				internal sealed class ConstructorProperties
				{
					internal global::System.Func<global::System.IO.Stream, global::System.IO.Stream>? Processor { get; init; }
				}
				
				internal static global::IHaveDelegate Instance(this global::Rocks.Expectations.Expectations<global::IHaveDelegate> @self, ConstructorProperties? @constructorProperties)
				{
					if (!@self.WasInstanceInvoked)
					{
						@self.WasInstanceInvoked = true;
						return @constructorProperties is null ?
							new RockIHaveDelegate(@self) :
							new RockIHaveDelegate(@self)
							{
								Processor = @constructorProperties.Processor!,
							};
					}
					else
					{
						throw new global::Rocks.Exceptions.NewMockInstanceException("Can only create a new mock once.");
					}
				}
				
				private sealed class RockIHaveDelegate
					: global::IHaveDelegate
				{
					private readonly global::System.Collections.Generic.Dictionary<int, global::System.Collections.Generic.List<global::Rocks.HandlerInformation>> handlers;
					
					public RockIHaveDelegate(global::Rocks.Expectations.Expectations<global::IHaveDelegate> @expectations) =>
						this.handlers = @expectations.Handlers;
					
					[global::Rocks.MemberIdentifier(0, "bool Equals(object? @obj)")]
					public override bool Equals(object? @obj)
					{
						if (this.handlers.TryGetValue(0, out var @methodHandlers))
						{
							foreach (var @methodHandler in @methodHandlers)
							{
								if (global::System.Runtime.CompilerServices.Unsafe.As<global::Rocks.Argument<object?>>(@methodHandler.Expectations[0]).IsValid(@obj))
								{
									var @result = @methodHandler.Method is not null ?
										global::System.Runtime.CompilerServices.Unsafe.As<global::System.Func<object?, bool>>(@methodHandler.Method)(@obj) :
										global::System.Runtime.CompilerServices.Unsafe.As<global::Rocks.HandlerInformation<bool>>(@methodHandler).ReturnValue;
									@methodHandler.IncrementCallCount();
									return @result!;
								}
							}
							
							throw new global::Rocks.Exceptions.ExpectationException("No handlers match for bool Equals(object? @obj)");
						}
						else
						{
							return base.Equals(@obj);
						}
					}
					
					[global::Rocks.MemberIdentifier(1, "int GetHashCode()")]
					public override int GetHashCode()
					{
						if (this.handlers.TryGetValue(1, out var @methodHandlers))
						{
							var @methodHandler = @methodHandlers[0];
							var @result = @methodHandler.Method is not null ?
								global::System.Runtime.CompilerServices.Unsafe.As<global::System.Func<int>>(@methodHandler.Method)() :
								global::System.Runtime.CompilerServices.Unsafe.As<global::Rocks.HandlerInformation<int>>(@methodHandler).ReturnValue;
							@methodHandler.IncrementCallCount();
							return @result!;
						}
						else
						{
							return base.GetHashCode();
						}
					}
					
					[global::Rocks.MemberIdentifier(2, "string? ToString()")]
					public override string? ToString()
					{
						if (this.handlers.TryGetValue(2, out var @methodHandlers))
						{
							var @methodHandler = @methodHandlers[0];
							var @result = @methodHandler.Method is not null ?
								global::System.Runtime.CompilerServices.Unsafe.As<global::System.Func<string?>>(@methodHandler.Method)() :
								global::System.Runtime.CompilerServices.Unsafe.As<global::Rocks.HandlerInformation<string?>>(@methodHandler).ReturnValue;
							@methodHandler.IncrementCallCount();
							return @result!;
						}
						else
						{
							return base.ToString();
						}
					}
					
					[global::Rocks.MemberIdentifier(3, "void Foo()")]
					public override void Foo()
					{
						if (this.handlers.TryGetValue(3, out var @methodHandlers))
						{
							var @methodHandler = @methodHandlers[0];
							if (@methodHandler.Method is not null)
							{
								global::System.Runtime.CompilerServices.Unsafe.As<global::System.Action>(@methodHandler.Method)();
							}
							
							@methodHandler.IncrementCallCount();
						}
						else
						{
							base.Foo();
						}
					}
					
				}
			}
			
			internal static class MethodExpectationsOfIHaveDelegateExtensions
			{
				internal static global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<object?, bool>, bool> Equals(this global::Rocks.Expectations.MethodExpectations<global::IHaveDelegate> @self, global::Rocks.Argument<object?> @obj)
				{
					global::System.ArgumentNullException.ThrowIfNull(@obj);
					return new global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<object?, bool>, bool>(@self.Add<bool>(0, new global::System.Collections.Generic.List<global::Rocks.Argument>(1) { @obj }));
				}
				internal static global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<int>, int> GetHashCode(this global::Rocks.Expectations.MethodExpectations<global::IHaveDelegate> @self) =>
					new global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<int>, int>(@self.Add<int>(1, new global::System.Collections.Generic.List<global::Rocks.Argument>()));
				internal static global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<string?>, string?> ToString(this global::Rocks.Expectations.MethodExpectations<global::IHaveDelegate> @self) =>
					new global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Func<string?>, string?>(@self.Add<string?>(2, new global::System.Collections.Generic.List<global::Rocks.Argument>()));
				internal static global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Action> Foo(this global::Rocks.Expectations.MethodExpectations<global::IHaveDelegate> @self) =>
					new global::Rocks.MethodAdornments<global::IHaveDelegate, global::System.Action>(@self.Add(3, new global::System.Collections.Generic.List<global::Rocks.Argument>()));
			}
			
			""";

		await TestAssistants.RunAsync<RockCreateGenerator>(code,
			new[] { (typeof(RockCreateGenerator), "IHaveDelegate_Rock_Create.g.cs", generatedCode) },
			Enumerable.Empty<DiagnosticResult>()).ConfigureAwait(false);
	}

	[Test]
	public static async Task GenerateWhenNamesAreKeywordsAsync()
	{
		var code =
			"""
			using Rocks;
			
			public interface IUseKeyword
			{
			    void Foo(string @namespace, string @event, string @property);   
			}

			public static class Test
			{
				public static void Go()
				{
					var expectations = Rock.Create<IUseKeyword>();
				}
{'fraction_non_alphanumeric': 0.1238927011852776, 'fraction_numerical': 0.002495321272613849, 'mean_word_length': 3.7180694526191878, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '5319435', 'n_tokens_mistral': 3082, 'n_tokens_neox': 2286, 'n_words': 407}