I wanted to switch things up and get aider set up on my laptop. The setup was pretty painless overall, but it didn’t leave me much time for actual ai experimentation.

I did get to do a little so let’s check it out!

Check our Conventions

I wasn’t actually sure the tool understood what conventions it was being fed. I asked it to reword them for me.

Prompt:

Can you repeat all of the conventions I’ve given you and rephrase them in your own words?

Details

C# / .NET Coding Conventions

  • Follow Resharper styling guidelines
  • Use var for variable declarations when the type is obvious
  • Use file-scoped namespaces instead of block-style namespaces
  • Prefer early returns to reduce nesting and improve readability
  • Always use braces for if statements, even for single-line blocks
  • Use NUnit as the testing framework rather than xUnit
  • Use Moq for mocking in tests
  • Method names should use CamelCase (including test methods)
  • Utilize the latest C# language features
  • Name tests in the format “Should” so the class name + test name forms a complete sentence
  • Each class, record, interface, or enum must be in its own file with a matching filename

General Coding Principles

  • Write simple, straightforward code rather than clever solutions
  • Keep code minimal while still achieving the goal
  • Ensure code is testable
  • Name variables and functions to clearly express their intent
  • Consider extracting functionality into well-named functions instead of adding comments
  • Maintain consistency with existing code style
  • Use tabs for indentation rather than spaces
  • Prefer pure functions and functional design patterns
  • Use dependency injection where appropriate
  • Tests should properly test functionality, not just hardcode expected responses
  • Avoid code duplication by refactoring shared functionality and constants
  • Remove dead/unused code when making changes
  • Only implement test stubs when explicitly asked to do so
  • When modifying code, ensure tests still compile without changing test assertions unless specifically requested

Tokens: 2.9k sent, 315 received. Cost: $0.01 message, $0.01 session.

Verdict: ✅ It did a nice job of summarizing my conventions!

Run the tests

Prompt:

run the unit tests

Details

To run the unit tests for this .NET project, you can use the following command:

dotnet test llm-history-to-post/tests/tests.csproj

This will execute all the NUnit tests in the test project.

Tokens: 5.6k sent, 48 received. Cost: $0.02 message, $0.03 session.
llm-history-to-post/tests/tests.csproj
Add file to the chat? (Y)es/(N)o/(D)on’t ask again [Yes]: n
dotnet test llm-history-to-post/tests/tests.csproj
Run shell command? (Y)es/(N)o/(D)on’t ask again [Yes]: y
Running dotnet test llm-history-to-post/tests/tests.csproj
Add command output to the chat? (Y)es/(N)o/(D)on’t ask again [Yes]: y
Added 360 lines of output to the chat.

Verdict: ✅ It successfully ran the tests.

Try 1 fixing errors

Prompt:

can you fix the test errors? this is the first time I’m running the tests on mac, I still need to the tests to pass on their previous environment

Details

I need to see the content of the FilePathUtilityTests.cs file to fix the test errors. Could you please add this file to the chat?

Tokens: 11k sent, 29 received. Cost: $0.03 message, $0.07 session.
llm-history-to-post/tests/Services/FilePathUtilityTests.cs
Add file to the chat? (Y)es/(N)o/(D)on’t ask again [Yes]: y

I’ll fix the test errors in the FilePathUtilityTests.cs file. The issue is that on macOS, temporary paths created with Path.GetTempPath() are actually symlinks that resolve to paths with “/private” prefix, but the tests are expecting the non-prefixed paths.

Let’s modify the tests to handle this platform difference:

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
	[Test]
	public void ShouldReturnFilePathWhenFileExists()
	{
		// Arrange
		var testFileName = "test.txt";
		var testFilePath = Path.Combine(_testDirectory, testFileName);
		File.WriteAllText(testFilePath, "Test content");
		
		// Act
		var result = FilePathUtility.FindFileInDirectoryTree(testFileName);
		
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(result, Is.EqualTo(testFilePath));
	}
=======
	[Test]
	public void ShouldReturnFilePathWhenFileExists()
	{
		// Arrange
		var testFileName = "test.txt";
		var testFilePath = Path.Combine(_testDirectory, testFileName);
		File.WriteAllText(testFilePath, "Test content");
		
		// Act
		var result = FilePathUtility.FindFileInDirectoryTree(testFileName);
		
		// Assert
		Assert.That(result, Is.Not.Null);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(testFilePath)));
	}
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
	[Test]
	public void ShouldReturnPathWhenDirectoryExists()
	{
		// Arrange
		// Create a content/post directory structure
		var contentDir = Path.Combine(_testDirectory, "content");
		var postDir = Path.Combine(contentDir, "post");
		var yearDir = Path.Combine(postDir, "2025");
		var monthDir = Path.Combine(yearDir, "04");
		Directory.CreateDirectory(monthDir);

		// Act
		var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);

		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(result, Is.EqualTo(monthDir));
	}
=======
	[Test]
	public void ShouldReturnPathWhenDirectoryExists()
	{
		// Arrange
		// Create a content/post directory structure
		var contentDir = Path.Combine(_testDirectory, "content");
		var postDir = Path.Combine(contentDir, "post");
		var yearDir = Path.Combine(postDir, "2025");
		var monthDir = Path.Combine(yearDir, "04");
		Directory.CreateDirectory(monthDir);

		// Act
		var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);

		// Assert
		Assert.That(result, Is.Not.Null);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(monthDir)));
	}
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
	[Test]
	public void ShouldCreateDateFoldersWhenContentDirectoryExists()
	{
		// Arrange
		// Create only the content directory but not the year/month structure
		var contentDir = Path.Combine(_testDirectory, "content");
		Directory.CreateDirectory(contentDir);
		
		// Expected path that should be created
		var expectedPath = Path.Combine(contentDir, "post", "2025", "04");
		
		// Act
		var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);
		
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(Directory.Exists(result), Is.True);
		Assert.That(result, Is.EqualTo(expectedPath));
	}
=======
	[Test]
	public void ShouldCreateDateFoldersWhenContentDirectoryExists()
	{
		// Arrange
		// Create only the content directory but not the year/month structure
		var contentDir = Path.Combine(_testDirectory, "content");
		Directory.CreateDirectory(contentDir);
		
		// Expected path that should be created
		var expectedPath = Path.Combine(contentDir, "post", "2025", "04");
		
		// Act
		var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);
		
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(Directory.Exists(result), Is.True);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(expectedPath)));
	}
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
			// Expected path that should be found and created
			var expectedPath = Path.Combine(contentDir, "post", "2025", "04");
			
			// Act
			var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);
			
			// Assert
			Assert.That(result, Is.Not.Null);
			Assert.That(Directory.Exists(result), Is.True);
			Assert.That(result, Is.EqualTo(expectedPath));
=======
			// Expected path that should be found and created
			var expectedPath = Path.Combine(contentDir, "post", "2025", "04");
			
			// Act
			var result = FilePathUtility.FindOrCreateBlogPostDirectory(2025, 4);
			
			// Assert
			Assert.That(result, Is.Not.Null);
			Assert.That(Directory.Exists(result), Is.True);
			// Use Path.GetFullPath to normalize paths for cross-platform compatibility
			Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(expectedPath)));
>>>>>>> REPLACE

Now run the tests again to see if they pass:

dotnet test llm-history-to-post/tests/tests.csproj

Tokens: 12k sent, 1.2k received. Cost: $0.06 message, $0.12 session.
Applied edit to llm-history-to-post/tests/Services/FilePathUtilityTests.cs
Commit 8e9740e feat: Update FilePathUtilityTests to use Path.GetFullPath for cross-platform path comparison
dotnet test llm-history-to-post/tests/tests.csproj
Run shell command? (Y)es/(N)o/(D)on’t ask again [Yes]: y
Running dotnet test llm-history-to-post/tests/tests.csproj
Add command output to the chat? (Y)es/(N)o/(D)on’t ask again [Yes]: y
Added 326 lines of output to the chat.
You can use /undo to undo and discard each aider commit.

Verdict: ❌ The tests failed with the same error.

Actually fix them

Prompt:

your fix didn’t seem to make a difference?

Details

You’re right, the issue persists. Let’s try a different approach. On macOS, the /var directory is actually a symlink to /private/var, which is why we’re seeing this difference. We need to normalize the paths in a way that handles this macOS-specific behavior.

Let’s modify the tests to use a custom path comparison method:

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
using LlmHistoryToPost.Services;

namespace LlmHistoryToPost.Tests.Services;
=======
using LlmHistoryToPost.Services;
using System.Runtime.InteropServices;

namespace LlmHistoryToPost.Tests.Services;
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
	private string _testDirectory;
	private string _originalDirectory;
=======
	private string _testDirectory;
	private string _originalDirectory;
	
	// Helper method to normalize paths for comparison on macOS
	private static bool PathsAreEqual(string path1, string path2)
	{
		// Normalize paths to handle macOS /private prefix
		if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
		{
			// Remove "/private" prefix if it exists
			path1 = path1.Replace("/private/var", "/var");
			path2 = path2.Replace("/private/var", "/var");
		}
		
		return Path.GetFullPath(path1) == Path.GetFullPath(path2);
	}
>>>>>>> REPLACE

Now let’s update each test to use this helper method:

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
		// Assert
		Assert.That(result, Is.Not.Null);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(testFilePath)));
=======
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(PathsAreEqual(result!, testFilePath), Is.True, 
			$"Paths don't match: '{result}' vs '{testFilePath}'");
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
		// Assert
		Assert.That(result, Is.Not.Null);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(monthDir)));
=======
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(PathsAreEqual(result!, monthDir), Is.True,
			$"Paths don't match: '{result}' vs '{monthDir}'");
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(Directory.Exists(result), Is.True);
		// Use Path.GetFullPath to normalize paths for cross-platform compatibility
		Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(expectedPath)));
=======
		// Assert
		Assert.That(result, Is.Not.Null);
		Assert.That(Directory.Exists(result), Is.True);
		Assert.That(PathsAreEqual(result!, expectedPath), Is.True,
			$"Paths don't match: '{result}' vs '{expectedPath}'");
>>>>>>> REPLACE

llm-history-to-post/tests/Services/FilePathUtilityTests.cs

<<<<<<< SEARCH
			// Assert
			Assert.That(result, Is.Not.Null);
			Assert.That(Directory.Exists(result), Is.True);
			// Use Path.GetFullPath to normalize paths for cross-platform compatibility
			Assert.That(Path.GetFullPath(result), Is.EqualTo(Path.GetFullPath(expectedPath)));
=======
			// Assert
			Assert.That(result, Is.Not.Null);
			Assert.That(Directory.Exists(result), Is.True);
			Assert.That(PathsAreEqual(result!, expectedPath), Is.True,
				$"Paths don't match: '{result}' vs '{expectedPath}'");
>>>>>>> REPLACE

Now run the tests again:

dotnet test llm-history-to-post/tests/tests.csproj

Tokens: 19k sent, 857 received. Cost: $0.07 message, $0.19 session.
Applied edit to llm-history-to-post/tests/Services/FilePathUtilityTests.cs
Commit 84811f5 test: Fix macOS path comparison in FilePathUtilityTests
dotnet test llm-history-to-post/tests/tests.csproj
Run shell command? (Y)es/(N)o/(D)on’t ask again [Yes]: y
Running dotnet test llm-history-to-post/tests/tests.csproj
Add command output to the chat? (Y)es/(N)o/(D)on’t ask again [Yes]: n
You can use /undo to undo and discard each aider commit.

Verdict: ✅ I’m not fully convinced this is the exact right way to do this, but it seems clean enough from the code perspective, so I’ll take it for now.

Conclusion

Getting the new machine setup was pretty quick! And now I’m not constrained to my desk working on this endeavor :).