diff --git a/.coderabbit.yaml b/.coderabbit.yaml
index ff17a25d..3d242d98 100644
--- a/.coderabbit.yaml
+++ b/.coderabbit.yaml
@@ -8,6 +8,16 @@ reviews:
- "!**/*.csv" # Exclude CSV data files
- "!**/*.xml" # Exclude XML files
- "!**/*.json" # Exclude JSON files
+ - "!**/*.dll" # Exclude DLL files
+ - "!**/*.pdb" # Exclude PDB files
+ - "!**/*.sln" # Exclude Solution files
+ - "!**/*.csproj" # Exclude Project files
+ - "!**/*.ndproj" # Exclude NDepend project files
+ - "!**/*.user" # Exclude User files
+ - "!**/*.suo" # Exclude Solution User Options
+ - "!**/*.cache" # Exclude Cache files
+ - "!**/*.yml" # Exclude YAML files
+ - "!**/*.yaml" # Exclude YAML files
- "!**/bin/**" # Exclude bin directories
- "!**/obj/**" # Exclude obj directories
- "!**/BenchmarkDotNet.Artifacts/**" # Exclude benchmark artifacts
@@ -28,3 +38,17 @@ reviews:
- "!**/*.Quantower.Tests.cs" # Exclude Quantower adapter tests
- "!**/*.Quantower.cs" # Exclude Quantower adapters
- "!**/perf/**" # Exclude performance tests
+ - "!**/quantower/**" # Exclude root quantower directory
+ - "!**/Mocks/**" # Exclude Mocks
+ - "!**/test_collection_expr.cs" # Exclude scratch files
+ - "!**/*.so" # Exclude Shared Objects
+ - "!**/*.dylib" # Exclude Dynamic Libraries
+ - "!**/*.log" # Exclude Log files
+ - "!**/*.png" # Exclude PNG images
+ - "!**/*.jpg" # Exclude JPG images
+ - "!**/*.jpeg" # Exclude JPEG images
+ - "!**/*.gif" # Exclude GIF images
+ - "!**/*.props" # Exclude Build properties
+ - "!**/*.targets" # Exclude Build targets
+ - "!**/*.db" # Exclude Database files
+ - "!**/*.sqlite" # Exclude SQLite files
diff --git a/.github/scanner.sh b/.github/scanner.sh
index a31085a7..e89b24a7 100644
--- a/.github/scanner.sh
+++ b/.github/scanner.sh
@@ -119,8 +119,16 @@ if [ "$SKIP_BUILD" = false ]; then
dotnet build /p:DisableGitVersionTask=true /p:Version=0.0.0-wsl /p:AssemblyVersion=0.0.0.0 /p:FileVersion=0.0.0.0
log_info "Running tests with coverage..."
+ set +e
dotnet test --no-build --collect:"XPlat Code Coverage" \
- -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover,lcov || true
+ -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover,lcov
+ TEST_EXIT_CODE=$?
+ set -e
+
+ if [ $TEST_EXIT_CODE -ne 0 ]; then
+ log_error "Tests failed with exit code $TEST_EXIT_CODE. Stopping analysis."
+ exit $TEST_EXIT_CODE
+ fi
# Copy coverage files to Qodana directory and convert Windows paths to Linux
log_info "Copying coverage files for Qodana..."
@@ -175,18 +183,38 @@ if [ "$SKIP_CODACY" = false ]; then
log_info "Uploading coverage to Codacy..."
# Find the most recent coverage files (one per test project)
- coverage_files=$(find . -name "coverage.opencover.xml" -type f -printf '%T@ %p\n' | sort -rn | head -2 | cut -d' ' -f2-)
+ mapfile -t coverage_files < <(find . -name "coverage.opencover.xml" -type f -printf '%T@ %p\n' | sort -rn | head -2 | cut -d' ' -f2-)
- if [ -n "$coverage_files" ]; then
- for file in $coverage_files; do
+ if [ ${#coverage_files[@]} -gt 0 ]; then
+ # Download and verify Codacy reporter
+ CODACY_VERSION="14.1.0"
+ CODACY_SHA256="f1db13a9b21a9d161ddfeadf0cf6a65ffb0e9eaae8c314d3d14502946ee08475"
+ CODACY_URL="https://github.com/codacy/codacy-coverage-reporter/releases/download/${CODACY_VERSION}/codacy-coverage-reporter-linux"
+ CODACY_BIN="/tmp/codacy-coverage-reporter"
+
+ log_info "Downloading Codacy coverage reporter v${CODACY_VERSION}..."
+ curl -L -o "$CODACY_BIN" "$CODACY_URL"
+
+ # Verify hash
+ echo "$CODACY_SHA256 $CODACY_BIN" | sha256sum -c -
+ if [ $? -ne 0 ]; then
+ log_error "Codacy reporter checksum verification failed!"
+ rm -f "$CODACY_BIN"
+ exit 1
+ fi
+
+ chmod +x "$CODACY_BIN"
+
+ for file in "${coverage_files[@]}"; do
log_detail "Uploading: $file"
- bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r "$file" --partial || true
+ "$CODACY_BIN" report -r "$file" --partial || true
done
# Send final notification
log_detail "Finalizing coverage report..."
- bash <(curl -Ls https://coverage.codacy.com/get.sh) final || true
+ "$CODACY_BIN" final || true
+ rm -f "$CODACY_BIN"
log_success "Codacy: https://app.codacy.com/gh/mihakralj/QuanTAlib/dashboard"
else
log_warn "No coverage.opencover.xml files found"
@@ -201,12 +229,21 @@ if [ "$SKIP_QODANA" = false ]; then
log_info "Starting Qodana analysis..."
# Install dependencies required for Qodana (IntelliJ) on minimal Debian
+ # Note: CI environments must run as root or have passwordless sudo configured
if ! dpkg -s libfreetype6 fontconfig &> /dev/null; then
log_info "Installing missing dependencies (libfreetype6, fontconfig)..."
+
if [ "$EUID" -ne 0 ]; then
- sudo apt-get update && sudo apt-get install -y libfreetype6 fontconfig
+ # Use sudo -n to fail fast if password is required
+ if ! sudo -n apt-get update || ! sudo -n DEBIAN_FRONTEND=noninteractive apt-get install -y libfreetype6 fontconfig; then
+ log_error "Dependency installation failed. Ensure passwordless sudo is configured."
+ exit 1
+ fi
else
- apt-get update && apt-get install -y libfreetype6 fontconfig
+ if ! apt-get update || ! DEBIAN_FRONTEND=noninteractive apt-get install -y libfreetype6 fontconfig; then
+ log_error "Dependency installation failed."
+ exit 1
+ fi
fi
fi
diff --git a/.github/sonarscanner.sh b/.github/sonarscanner.sh
index f9ce1864..e75365ac 100644
--- a/.github/sonarscanner.sh
+++ b/.github/sonarscanner.sh
@@ -28,12 +28,19 @@ dotnet sonarscanner begin \
echo "==> Building solution..."
dotnet build --no-incremental
+if [ $? -ne 0 ]; then
+ echo "Error: Build failed"
+ exit 1
+fi
echo "==> Running tests with coverage..."
mkdir -p "$COVERAGE_DIR"
-# Run tests with both formats if possible, or sequentially
dotnet test --no-build --collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=lcov,opencover
+if [ $? -ne 0 ]; then
+ echo "Error: Tests failed"
+ exit 1
+fi
# Copy coverage to Qodana directory
find . -name "coverage.info" -exec cp {} "$COVERAGE_DIR/" \;
diff --git a/lib/core/simd/SimdExtensions.cs b/lib/core/simd/SimdExtensions.cs
index 9cf53d30..efcde1ae 100644
--- a/lib/core/simd/SimdExtensions.cs
+++ b/lib/core/simd/SimdExtensions.cs
@@ -266,8 +266,8 @@ public static class SimdExtensions
}
///
- /// Calculates variance using SIMD vectorization (Welford's online algorithm adapted).
- /// More numerically stable than naive two-pass algorithm.
+ /// Calculates variance using a two-pass SIMD variant that computes the mean first (via AverageSIMD) and then sums squared differences to produce variance.
+ /// Note that this is not the single-pass Welford algorithm.
/// Returns NaN if any input value is non-finite or if mean is non-finite.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/lib/core/tseries/TSeries.Tests.cs b/lib/core/tseries/TSeries.Tests.cs
index a6379dc6..459cb078 100644
--- a/lib/core/tseries/TSeries.Tests.cs
+++ b/lib/core/tseries/TSeries.Tests.cs
@@ -1,8 +1,8 @@
-namespace QuanTAlib.Tests
+namespace QuanTAlib.Tests;
+
+public class TSeriesTests
{
- public class TSeriesTests
- {
[Fact]
public void Constructor_Default_CreatesEmptySeries()
{
@@ -284,9 +284,8 @@ namespace QuanTAlib.Tests
series.Add(100, 1.0);
series.Add(200, 2.0);
- IEnumerable enumerable = series;
var list = new List