Skip to content
Open
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
60 changes: 60 additions & 0 deletions .codetesting/AnalysisReport_20251009_223825_262.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Test Failures due possible code bugs

## Core.UnitTests.csproj - GetLerp_InterfaceType_ReturnsObjectLerp
- **Confidence**: High
- **Test File**: src/Core/tests/UnitTests/Animations/LerpTests.cs
- **Bug Location**: src/Core/src/Animations/Lerp.cs@174

### Analysis
The GetLerp method has a logic flaw when handling interface types. Interface types like IDisposable don't have BaseType properties (BaseType is null), so the method fails to find the object Lerp that should be returned as a fallback. The method only walks the BaseType hierarchy but doesn't account for interfaces that should inherit from object conceptually. The test is correct in expecting that interface types should return the object Lerp.

### Suggested Fix
The GetLerp method needs to be modified to handle interface types. When the BaseType chain traversal is complete and no Lerp is found, the method should fall back to checking for typeof(object) in the Lerps dictionary. This can be done by adding a final fallback check: `if (lerp == null && type.IsInterface) { Lerps.TryGetValue(typeof(object), out lerp); }` before the return statement, or more generally, always try the object type as a final fallback.

## Core.UnitTests.csproj - GetLerp_NullType_ReturnsNull
- **Confidence**: High
- **Test File**: src/Core/tests/UnitTests/Animations/LerpTests.cs
- **Bug Location**: src/Core/src/Animations/Lerp.cs@177

### Analysis
The GetLerp method throws ArgumentNullException when passed a null Type parameter because Dictionary.TryGetValue does not accept null keys. The method should handle null input gracefully and return null as expected by the test. The issue is in the production code at line 177 where it attempts to use the null type parameter as a dictionary key without first checking for null.

### Suggested Fix
The GetLerp method needs to add a null check at the beginning. The fix would be to add `if (type == null) return null;` before line 177. This would handle the null case gracefully and prevent the ArgumentNullException from being thrown when trying to use null as a dictionary key.

## Core.UnitTests.csproj - IndexOfChar_NullString_ThrowsArgumentNullException
- **Confidence**: High
- **Test File**: src/Core/tests/UnitTests/Extensions/StringExtensionsTests.cs
- **Bug Location**: src/Core/src/Extensions/StringExtensions.cs@19

### Analysis
The IndexOfChar extension method does not perform null checking on its toSearch parameter. When a null string is passed, it attempts to call IndexOf on the null reference, resulting in a NullReferenceException instead of the expected ArgumentNullException. The test is correctly expecting an ArgumentNullException for null input, which is the standard behavior for string methods.

### Suggested Fix
The IndexOfChar method needs null parameter validation. Add a null check at the beginning of the method: `if (toSearch == null) throw new ArgumentNullException(nameof(toSearch));`. The fixed method should look like:

```csharp
public static int IndexOfChar(this string toSearch, char character)
{
if (toSearch == null)
throw new ArgumentNullException(nameof(toSearch));

#if NETSTANDARD2_0
return toSearch.IndexOf(character);
#else
return toSearch.IndexOf(character, StringComparison.Ordinal);
#endif
}
```

## Core.UnitTests.csproj - TryGetTarget_WeakReferenceWithIncompatibleTarget_ReturnsFalseAndSetsTargetToNull
- **Confidence**: High
- **Test File**: src/Core/tests/UnitTests/WeakReferenceExtensionsTests.cs
- **Bug Location**: src/Core/src/WeakReferenceExtensions.cs@14

### Analysis
The TryGetTarget<T> method in WeakReferenceExtensions.cs performs a direct cast on line 14 without checking type compatibility. When the WeakReference contains an integer (42) and we try to get it as a string, the cast (T?)self.Target throws an InvalidCastException. The test correctly expects the method to return false and set target to null for incompatible types, but the production code doesn't handle this scenario gracefully.

### Suggested Fix
The TryGetTarget<T> method needs to be modified to check type compatibility before casting. Replace line 14 with: `target = self.Target is T validTarget ? validTarget : null;` This will safely check if the target is of the correct type and assign it if compatible, or null if not, instead of throwing an exception.

328 changes: 194 additions & 134 deletions src/Core/tests/UnitTests/Animations/EasingTests.cs
Original file line number Diff line number Diff line change
@@ -1,139 +1,199 @@
using System;
using System;

using Microsoft.Maui;
using Microsoft.Maui.Converters;
using Xunit;

namespace Microsoft.Maui.UnitTests
{
[Category(TestCategory.Animations)]
public class EasingTests
{
[Theory]
[InlineData(0.0)]
[InlineData(1.0)]
[InlineData(2.0)]
[InlineData(5.0)]
[InlineData(8.0)]
[InlineData(9.0)]
[InlineData(10.0)]
public void Linear(double input)
{
Assert.Equal(input, Easing.Linear.Ease(input));
}

[Theory]
[InlineData(0.0)]
[InlineData(1.0)]
public void AllRunFromZeroToOne(double val)
{
const double epsilon = 0.001;

Assert.True(Math.Abs(val - Easing.Linear.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.BounceIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.BounceOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicInOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinInOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SpringIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SpringOut.Ease(val)) < epsilon);
}

[Fact]
public void CanConvert()
{
var converter = new EasingTypeConverter();

Assert.True(converter.CanConvertFrom(typeof(string)));
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void NonTextEasingsAreNull(string input)
{
var converter = new EasingTypeConverter();

Assert.Null(converter.ConvertFromInvariantString(input));
}

[Fact]
public void CanConvertFromEasingNameToEasing()
{
var converter = new EasingTypeConverter();

Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("Linear"));
Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("linear"));
Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("Easing.Linear"));

Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("SinOut"));
Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("sinout"));
Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("Easing.SinOut"));

Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("SinIn"));
Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("sinin"));
Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("Easing.SinIn"));

Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("SinInOut"));
Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("sininout"));
Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("Easing.SinInOut"));

Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("CubicOut"));
Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("cubicout"));
Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("Easing.CubicOut"));

Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("CubicIn"));
Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("cubicin"));
Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("Easing.CubicIn"));

Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("CubicInOut"));
Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("cubicinout"));
Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("Easing.CubicInOut"));

Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("BounceOut"));
Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("bounceout"));
Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("Easing.BounceOut"));

Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("BounceIn"));
Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("bouncein"));
Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("Easing.BounceIn"));

Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("SpringOut"));
Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("springout"));
Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("Easing.SpringOut"));

Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("SpringIn"));
Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("springin"));
Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("Easing.SpringIn"));
}

[Fact]
public void CanConvertFromEasingToEasingName()
{
var converter = new EasingTypeConverter();

Assert.Equal("Linear", converter.ConvertToInvariantString(Easing.Linear));
Assert.Equal("SinOut", converter.ConvertToInvariantString(Easing.SinOut));
Assert.Equal("SinIn", converter.ConvertToInvariantString(Easing.SinIn));
Assert.Equal("SinInOut", converter.ConvertToInvariantString(Easing.SinInOut));
Assert.Equal("CubicOut", converter.ConvertToInvariantString(Easing.CubicOut));
Assert.Equal("CubicIn", converter.ConvertToInvariantString(Easing.CubicIn));
Assert.Equal("CubicInOut", converter.ConvertToInvariantString(Easing.CubicInOut));
Assert.Equal("BounceOut", converter.ConvertToInvariantString(Easing.BounceOut));
Assert.Equal("BounceIn", converter.ConvertToInvariantString(Easing.BounceIn));
Assert.Equal("SpringOut", converter.ConvertToInvariantString(Easing.SpringOut));
Assert.Equal("SpringIn", converter.ConvertToInvariantString(Easing.SpringIn));
}

[Fact]
public void InvalidEasingNamesThrow()
{
var converter = new EasingTypeConverter();

Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("WrongEasingName"));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("Easing.Linear.SinInOut"));
}
}
}
[Category(TestCategory.Animations)]
public class EasingTests
{
[Theory]
[InlineData(0.0)]
[InlineData(1.0)]
[InlineData(2.0)]
[InlineData(5.0)]
[InlineData(8.0)]
[InlineData(9.0)]
[InlineData(10.0)]
public void Linear(double input)
{
Assert.Equal(input, Easing.Linear.Ease(input));
}

[Theory]
[InlineData(0.0)]
[InlineData(1.0)]
public void AllRunFromZeroToOne(double val)
{
const double epsilon = 0.001;

Assert.True(Math.Abs(val - Easing.Linear.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.BounceIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.BounceOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicInOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.CubicOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinInOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SinOut.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SpringIn.Ease(val)) < epsilon);
Assert.True(Math.Abs(val - Easing.SpringOut.Ease(val)) < epsilon);
}

[Fact]
public void CanConvert()
{
var converter = new EasingTypeConverter();

Assert.True(converter.CanConvertFrom(typeof(string)));
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void NonTextEasingsAreNull(string input)
{
var converter = new EasingTypeConverter();

Assert.Null(converter.ConvertFromInvariantString(input));
}

[Fact]
public void CanConvertFromEasingNameToEasing()
{
var converter = new EasingTypeConverter();

Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("Linear"));
Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("linear"));
Assert.Equal(Easing.Linear, converter.ConvertFromInvariantString("Easing.Linear"));

Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("SinOut"));
Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("sinout"));
Assert.Equal(Easing.SinOut, converter.ConvertFromInvariantString("Easing.SinOut"));

Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("SinIn"));
Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("sinin"));
Assert.Equal(Easing.SinIn, converter.ConvertFromInvariantString("Easing.SinIn"));

Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("SinInOut"));
Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("sininout"));
Assert.Equal(Easing.SinInOut, converter.ConvertFromInvariantString("Easing.SinInOut"));

Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("CubicOut"));
Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("cubicout"));
Assert.Equal(Easing.CubicOut, converter.ConvertFromInvariantString("Easing.CubicOut"));

Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("CubicIn"));
Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("cubicin"));
Assert.Equal(Easing.CubicIn, converter.ConvertFromInvariantString("Easing.CubicIn"));

Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("CubicInOut"));
Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("cubicinout"));
Assert.Equal(Easing.CubicInOut, converter.ConvertFromInvariantString("Easing.CubicInOut"));

Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("BounceOut"));
Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("bounceout"));
Assert.Equal(Easing.BounceOut, converter.ConvertFromInvariantString("Easing.BounceOut"));

Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("BounceIn"));
Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("bouncein"));
Assert.Equal(Easing.BounceIn, converter.ConvertFromInvariantString("Easing.BounceIn"));

Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("SpringOut"));
Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("springout"));
Assert.Equal(Easing.SpringOut, converter.ConvertFromInvariantString("Easing.SpringOut"));

Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("SpringIn"));
Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("springin"));
Assert.Equal(Easing.SpringIn, converter.ConvertFromInvariantString("Easing.SpringIn"));
}

[Fact]
public void CanConvertFromEasingToEasingName()
{
var converter = new EasingTypeConverter();

Assert.Equal("Linear", converter.ConvertToInvariantString(Easing.Linear));
Assert.Equal("SinOut", converter.ConvertToInvariantString(Easing.SinOut));
Assert.Equal("SinIn", converter.ConvertToInvariantString(Easing.SinIn));
Assert.Equal("SinInOut", converter.ConvertToInvariantString(Easing.SinInOut));
Assert.Equal("CubicOut", converter.ConvertToInvariantString(Easing.CubicOut));
Assert.Equal("CubicIn", converter.ConvertToInvariantString(Easing.CubicIn));
Assert.Equal("CubicInOut", converter.ConvertToInvariantString(Easing.CubicInOut));
Assert.Equal("BounceOut", converter.ConvertToInvariantString(Easing.BounceOut));
Assert.Equal("BounceIn", converter.ConvertToInvariantString(Easing.BounceIn));
Assert.Equal("SpringOut", converter.ConvertToInvariantString(Easing.SpringOut));
Assert.Equal("SpringIn", converter.ConvertToInvariantString(Easing.SpringIn));
}

[Fact]
public void InvalidEasingNamesThrow()
{
var converter = new EasingTypeConverter();

Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("WrongEasingName"));
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("Easing.Linear.SinInOut"));
}
}

public class EasingDefaultPropertyTests
{
/// <summary>
/// Tests that the Default property returns a non-null Easing instance.
/// Verifies the basic contract that Default provides a valid easing function.
/// Expected result: Default property returns a non-null Easing instance.
/// </summary>
[Fact]
[Trait("Owner", "Code Testing Agent 0.4.133-alpha+a413c4336c")]
[Trait("Category", "auto-generated")]
public void Default_Always_ReturnsNonNullInstance()
{
// Act
var result = Easing.Default;

// Assert
Assert.NotNull(result);
}

/// <summary>
/// Tests that the Default property returns the same instance as CubicInOut.
/// Verifies that Default is correctly configured to use the CubicInOut easing function as documented.
/// Expected result: Default property returns the exact same instance as CubicInOut.
/// </summary>
[Fact]
[Trait("Owner", "Code Testing Agent 0.4.133-alpha+a413c4336c")]
[Trait("Category", "auto-generated")]
public void Default_Always_ReturnsCubicInOutInstance()
{
// Arrange
var cubicInOut = Easing.CubicInOut;

// Act
var result = Easing.Default;

// Assert
Assert.Same(cubicInOut, result);
}

/// <summary>
/// Tests that the Default property returns the same instance on multiple calls.
/// Verifies the property provides consistent behavior and maintains reference equality.
/// Expected result: Multiple accesses to Default return the same object reference.
/// </summary>
[Fact]
[Trait("Owner", "Code Testing Agent 0.4.133-alpha+a413c4336c")]
[Trait("Category", "auto-generated")]
public void Default_MultipleAccesses_ReturnsSameInstance()
{
// Act
var first = Easing.Default;
var second = Easing.Default;

// Assert
Assert.Same(first, second);
}
}
}
Loading
Loading