diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index bb07e743..35120582 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -12,5 +12,6 @@
false
false
false
+ enable
\ No newline at end of file
diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs
index 90777fb8..2a9f2bbc 100644
--- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs
+++ b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs
@@ -53,5 +53,58 @@ public void TableToStringWithAdditionalColumn()
table.ToString(new[] { "Additional" }, new[] { new[] { "SomeAdditional Value" } })
.ShouldMatchApproved();
}
+
+ [Fact]
+ public void Add_WhenColumnCountMismatch_Throws()
+ {
+ var table = new ExampleTable("A", "B");
+ var ex = Should.Throw(() => table.Add(1, 2, 3));
+ ex.Message.ShouldContain("Number of column values does not match");
+ }
+
+ [Fact]
+ public void CollectionOperations_WorkCorrectly()
+ {
+ var table = new ExampleTable("A");
+ table.Add("val1");
+ table.Add("val2");
+
+ table.Count.ShouldBe(2);
+ table.IsReadOnly.ShouldBeFalse();
+
+ var first = table.First();
+ table.Contains(first).ShouldBeTrue();
+ table.Remove(first).ShouldBeTrue();
+ table.Count.ShouldBe(1);
+
+ table.Clear();
+ table.Count.ShouldBe(0);
+ }
+
+ [Fact]
+ public void CopyTo_CopiesElements()
+ {
+ var table = new ExampleTable("A");
+ table.Add("x");
+ table.Add("y");
+
+ var array = new Example[3];
+ table.CopyTo(array, 1);
+
+ array[0].ShouldBeNull();
+ array[1].ShouldNotBeNull();
+ array[2].ShouldNotBeNull();
+ }
+
+ [Theory]
+ [InlineData("MyHeader", "my header", true)]
+ [InlineData("MyHeader", "my_header", true)]
+ [InlineData("MyHeader", "MYHEADER", true)]
+ [InlineData("MyHeader", "Other", false)]
+ [InlineData("MyHeader", null, false)]
+ public void HeaderMatches_VariousCases(string header, string? name, bool expected)
+ {
+ ExampleTable.HeaderMatches(header, name).ShouldBe(expected);
+ }
}
}
\ No newline at end of file
diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs
index 36b1dfbf..ca27accf 100644
--- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs
+++ b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs
@@ -1,4 +1,5 @@
-using Shouldly;
+using System;
+using Shouldly;
using Xunit;
namespace TestStack.BDDfy.Tests.Scanner.Examples
@@ -13,5 +14,92 @@ public void CanFormatAsStringTests()
new ExampleValue("Header", new object(), () => 0).GetValueAsString().ShouldBe("System.Object");
new ExampleValue("Header", new[] {1, 2}, () => 0).GetValueAsString().ShouldBe("1, 2");
}
+
+ [Fact]
+ public void GetValue_WhenTargetTypeMatchesDirectly_ReturnsValue()
+ {
+ var value = new ExampleValue("Col", 42, () => 0);
+ value.GetValue(typeof(int)).ShouldBe(42);
+ value.ValueHasBeenUsed.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void GetValue_WhenNullAndTargetIsNullable_ReturnsNull()
+ {
+ var value = new ExampleValue("Col", null, () => 0);
+ value.GetValue(typeof(int?)).ShouldBeNull();
+ value.ValueHasBeenUsed.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void GetValue_WhenNullAndTargetIsReferenceType_ReturnsNull()
+ {
+ var value = new ExampleValue("Col", null, () => 0);
+ value.GetValue(typeof(string)).ShouldBeNull();
+ }
+
+ [Fact]
+ public void GetValue_WhenNullAndTargetIsValueType_Throws()
+ {
+ var value = new ExampleValue("Col", null, () => 2);
+ var ex = Should.Throw(() => value.GetValue(typeof(int)));
+ ex.Message.ShouldContain("Cannot convert to Int32");
+ ex.Message.ShouldContain("Column: 'Col'");
+ ex.Message.ShouldContain("Row: 3");
+ }
+
+ [Theory]
+ [InlineData("123", typeof(int), 123)]
+ [InlineData("45.6", typeof(double), 45.6)]
+ [InlineData("true", typeof(bool), true)]
+ public void GetValue_UsesConvertChangeType(string input, Type targetType, object expected)
+ {
+ var value = new ExampleValue("Col", input, () => 0);
+ value.GetValue(targetType).ShouldBe(expected);
+ }
+
+ [Fact]
+ public void GetValue_WhenEnumString_ParsesEnum()
+ {
+ var value = new ExampleValue("Col", "Transition", () => 0);
+ value.GetValue(typeof(ExecutionOrder)).ShouldBe(ExecutionOrder.Transition);
+ }
+
+ [Fact]
+ public void GetValue_WhenDateTimeString_ParsesDateTime()
+ {
+ var value = new ExampleValue("Col", "2023-06-15", () => 0);
+ value.GetValue(typeof(DateTime)).ShouldBe(new DateTime(2023, 6, 15));
+ }
+
+ [Fact]
+ public void GetValue_WhenInvalidCast_ThrowsUnassignableExampleException()
+ {
+ var value = new ExampleValue("Col", new object(), () => 1);
+ var ex = Should.Throw(() => value.GetValue(typeof(int)));
+ ex.Message.ShouldContain("cannot be assigned to Int32");
+ ex.Message.ShouldContain("Column: 'Col'");
+ ex.Message.ShouldContain("Row: 2");
+ }
+
+ [Theory]
+ [InlineData("myHeader", "myHeader", true)]
+ [InlineData("my header", "myHeader", true)]
+ [InlineData("my_header", "myHeader", true)]
+ [InlineData("MyHeader", "myheader", true)]
+ [InlineData("Header1", "Header2", false)]
+ [InlineData("Header", null, false)]
+ public void MatchesName_VariousInputs(string header, string? name, bool expected)
+ {
+ var value = new ExampleValue(header, "x", () => 0);
+ value.MatchesName(name).ShouldBe(expected);
+ }
+
+ [Fact]
+ public void Row_ReturnsOneBasedIndex()
+ {
+ var value = new ExampleValue("Col", "x", () => 4);
+ value.Row.ShouldBe(5);
+ }
}
}
\ No newline at end of file
diff --git a/src/TestStack.BDDfy.Tests/TypeExtensionsTests.cs b/src/TestStack.BDDfy.Tests/TypeExtensionsTests.cs
new file mode 100644
index 00000000..1bf864fc
--- /dev/null
+++ b/src/TestStack.BDDfy.Tests/TypeExtensionsTests.cs
@@ -0,0 +1,60 @@
+using System;
+using Shouldly;
+using Xunit;
+
+namespace TestStack.BDDfy.Tests
+{
+ public class TypeExtensionsTests
+ {
+ [Theory]
+ [InlineData(typeof(int), true)]
+ [InlineData(typeof(string), false)]
+ [InlineData(typeof(DateTime), true)]
+ [InlineData(typeof(object), false)]
+ public void IsValueType_ReturnsExpected(Type type, bool expected)
+ {
+ type.IsValueType().ShouldBe(expected);
+ }
+
+ [Theory]
+ [InlineData(typeof(DayOfWeek), true)]
+ [InlineData(typeof(int), false)]
+ [InlineData(typeof(string), false)]
+ public void IsEnum_ReturnsExpected(Type type, bool expected)
+ {
+ type.IsEnum().ShouldBe(expected);
+ }
+
+ [Theory]
+ [InlineData(typeof(int?), true)]
+ [InlineData(typeof(System.Collections.Generic.List), true)]
+ [InlineData(typeof(int), false)]
+ [InlineData(typeof(string), false)]
+ public void IsGenericType_ReturnsExpected(Type type, bool expected)
+ {
+ type.IsGenericType().ShouldBe(expected);
+ }
+
+ [Fact]
+ public void IsInstanceOfType_ReturnsCorrectly()
+ {
+ typeof(string).IsInstanceOfType("hello").ShouldBeTrue();
+ typeof(int).IsInstanceOfType("hello").ShouldBeFalse();
+ typeof(object).IsInstanceOfType(42).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Assembly_ReturnsCorrectAssembly()
+ {
+ typeof(string).Assembly().ShouldBe(typeof(string).Assembly);
+ }
+
+ [Fact]
+ public void GetCustomAttributes_ReturnsAttributes()
+ {
+ var attrs = typeof(FlagsAttribute).GetCustomAttributes(typeof(AttributeUsageAttribute), true);
+ attrs.ShouldNotBeEmpty();
+ attrs[0].ShouldBeOfType();
+ }
+ }
+}
diff --git a/src/TestStack.BDDfy.Tests/WithTagsExtensionsTests.cs b/src/TestStack.BDDfy.Tests/WithTagsExtensionsTests.cs
new file mode 100644
index 00000000..9875994f
--- /dev/null
+++ b/src/TestStack.BDDfy.Tests/WithTagsExtensionsTests.cs
@@ -0,0 +1,33 @@
+using System.Linq;
+using Shouldly;
+using Xunit;
+
+namespace TestStack.BDDfy.Tests
+{
+ public class WithTagsExtensionsTests
+ {
+ [Fact]
+ public void WithTags_AddsTags_ToTestContext()
+ {
+ var testObject = new TestClass();
+ var result = testObject.WithTags("tag1", "tag2");
+
+ result.ShouldBeSameAs(testObject);
+ var context = TestContext.GetContext(testObject);
+ context.Tags.ShouldContain("tag1");
+ context.Tags.ShouldContain("tag2");
+ }
+
+ [Fact]
+ public void WithTags_CanBeCalledMultipleTimes()
+ {
+ var testObject = new TestClass();
+ testObject.WithTags("a").WithTags("b", "c");
+
+ var context = TestContext.GetContext(testObject);
+ context.Tags.Count.ShouldBe(3);
+ }
+
+ private class TestClass { }
+ }
+}
diff --git a/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs b/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs
index 9e6c5ed8..19e48e14 100644
--- a/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs
+++ b/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs
@@ -7,7 +7,7 @@ namespace TestStack.BDDfy.Processors
{
public static class AsyncTestRunner
{
- public static void Run(Func