Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/Cellm.Tests/Unit/AddIn/ArgumentParserTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,93 @@
using System.Runtime.CompilerServices;
using Cellm.AddIn;
using Cellm.AddIn.Exceptions;
using ExcelDna.Integration;
using Microsoft.Extensions.Configuration;
using Xunit;
using CellmRange = Cellm.AddIn.Range;

namespace Cellm.Tests.Unit.AddIn;

public class ArgumentParserTests
{
private static ArgumentParser CreateParser()
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["CellmAddInConfiguration:DefaultProvider"] = "OpenAi",
["CellmAddInConfiguration:DefaultTemperature"] = "0",
["OpenAiConfiguration:DefaultModel"] = "gpt-4.1",
})
.Build();

return new ArgumentParser(config);
}

// ExcelReference constructor calls into Excel, so we create an uninitialized instance for unit tests
private static ExcelReference CreateExcelReference() =>
(ExcelReference)RuntimeHelpers.GetUninitializedObject(typeof(ExcelReference));

#region Parse Old Syntax Tests

[Fact]
public void Parse_OldArgumentOrder_CellsThenString_ThrowsCellmException()
{
var parser = CreateParser();

var ex = Assert.Throws<CellmException>(() =>
parser
.AddInstructions(CreateExcelReference())
.AddCells(new object[] { "Extract keywords", ExcelMissing.Value })
.Parse());

Assert.Contains("argument order changed", ex.Message);
}

[Fact]
public void Parse_OldArgumentOrder_CellsThenStringThenTemperature_ThrowsCellmException()
{
var parser = CreateParser();

var ex = Assert.Throws<CellmException>(() =>
parser
.AddInstructions(CreateExcelReference())
.AddCells(new object[] { "Extract keywords", 0.7 })
.Parse());

Assert.Contains("argument order changed", ex.Message);
}

[Fact]
public void Parse_OldArgumentOrder_CellsThenTemperature_ThrowsCellmException()
{
var parser = CreateParser();

var ex = Assert.Throws<CellmException>(() =>
parser
.AddInstructions(CreateExcelReference())
.AddCells(new object[] { 0.7, ExcelMissing.Value })
.Parse());

Assert.Contains("argument order changed", ex.Message);
}

[Fact]
public void Parse_OldTemperatureArgument_StringThenTemperature_ThrowsCellmException()
{
var parser = CreateParser();

var ex = Assert.Throws<CellmException>(() =>
parser
.AddInstructions("Extract keywords")
.AddCells(new object[] { 0.7, ExcelMissing.Value })
.Parse());

Assert.Contains("temperature argument was removed", ex.Message);
}

#endregion

#region GetColumnName Tests

[Theory]
Expand Down
6 changes: 6 additions & 0 deletions src/Cellm/AddIn/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,16 @@ internal Arguments Parse()
{
// =PROMPT("Hello world")
(string instructions, []) => new Arguments(provider, model, [], instructions, temperature, _outputShape),
// Old temperature argument: =PROMPT("instruction", 0.7), =PROMPT("instruction", A1:B2, 0.7), etc.
(string, object[] ranges) when ranges.Any(r => r is double) =>
throw new CellmException("The temperature argument was removed in v0.5. Please use PROMPT(\"instruction\", A1:B2) and configure temperature via the ribbon UI."),
// =PROMPT("Hello world", A1, B2, ...)
(string instructions, object[] ranges) => new Arguments(provider, model, ParseRanges(ranges), instructions, temperature, _outputShape),
// =PROMPT(A1:B2)
(ExcelReference instructions, []) => new Arguments(provider, model, [], new Range(instructions.RowFirst, instructions.ColumnFirst, instructions.GetValue()), temperature, _outputShape),
// Old argument order: =PROMPT(A1:B2, "instruction"), =PROMPT(A1:B2, "instruction", 0.7), =PROMPT(A1:B2, 0.7), etc.
(ExcelReference, object[] ranges) when ranges.Any(r => r is string or double) =>
throw new CellmException("The argument order changed in v0.5. Please use PROMPT(\"instruction\", A1:B2) instead of PROMPT(A1:B2, \"instruction\"). Temperature is now configured via the ribbon UI."),
// =PROMPT(A1:B2, C1, D2, ...)
(ExcelReference instructions, object[] ranges) => new Arguments(provider, model, ParseRanges(ranges), new Range(instructions.RowFirst, instructions.ColumnFirst, instructions.GetValue()), temperature, _outputShape),
// Short-circuit if instructions contain an Excel error
Expand Down
Loading