Fix Nor 3/4-arity, timer state ordering, empty And/Or and timespan validation - #35
Merged
DevJasperNL merged 1 commit intoSep 5, 2026
Conversation
…lidation - Nor with three or four inputs returned OR because the trailing Not() was missing; both overloads now mirror Nand. - TimedBooleanOperator recorded LastSourceValue after dispatching to the subclass, so a timer that fires synchronously (Scheduler.Immediate) threw NullReferenceException and a value fed back re-entrantly from the observer was overwritten and lost. The value is now recorded first and the previous value is passed to OnSourceValue explicitly. Unsubscribe also sets the terminated flag before the timer is torn down. - All scheduling operators throw ArgumentOutOfRangeException for a zero or negative timespan, matching BlinkWhileTrue. Previously five of them returned the raw source (bypassing distinctUntilChanged and WhenTrueFor's initial false) and LimitTrueDuration accepted any value. - And/Or over an empty collection emit true/false and complete instead of never signalling; null observables and null elements throw at call time. - nuget-publish derives the version from the release that triggered the run instead of the newest tag in the repository. Adds regression tests for every fix: Nand/Nor truth tables across all overloads, re-entrant feedback, Scheduler.Immediate, empty and null inputs, and zero/negative timespans per operator.
DevJasperNL
deleted the
bugfix/nor-arity-timer-state-and-timespan-validation
branch
September 5, 2026 13:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Functional bug fixes found in a full review of the library, plus the regression tests that were missing for each of them.
Bugs fixed
Norwith three or four inputs returned OR (BooleanObservableExtensions.Operators.Or.cs)The 3- and 4-arity
Noroverloads were missing the trailing.Not(). With all inputsfalsethey emittedfalseinstead oftrue. There were noNortests at all, which is how it slipped through. Both overloads now delegate toOr(...).Not()exactly likeNand.Timer and re-entrancy state corruption (
TimedBooleanOperator.cs)LastSourceValuewas assigned after the subclass hook ran. Two concrete failures:WhenTrueFor(span, Scheduler.Immediate)threwNullReferenceExceptionon the firsttrue, because the immediate scheduler runs the timer inline whileLastSourceValueis still null.WhenStableFor, a fed-backfalsewas silently lost and the output stayedtrue.The value is now recorded before dispatching and the previous value is handed to
OnSourceValue(value, previous)explicitly. Unsubscribe also flips the terminated flag before the timer is disposed.Empty and null inputs to
And/OrCombineLatestover zero sources never emits and never completes, soArray.Empty<IObservable<bool>>().And()was a silentNever. An empty collection now emitstrueforAndandfalseforOrand completes. A null observable or a null element throws an argument exception at call time instead of aNullReferenceExceptionat subscribe time.Publish workflow used the wrong tag (
.github/workflows/nuget-publish.yml)The version came from the newest tag in the repository rather than the release that triggered the run, so a patch release on an older line would have been stamped with the wrong version. It now uses
github.event.release.tag_name.Breaking change
Zero or negative timespans now throw
ArgumentOutOfRangeExceptionin every scheduling operator, matching whatBlinkWhileTruealready did. PreviouslyTrueForAtLeast,PersistTrueFor,WhenTrueFor,WhenStableForandPulseTrueForreturned the raw source fortimeSpan <= Zero, which bypasseddistinctUntilChangedandWhenTrueFor's "first output is always false" contract, andLimitTrueDurationaccepted any value and silently forcedfalseright after everytruefor a negative span. The XML docs and the README (Common options) document the new behaviour.Tests
Nand/Nortruth tables for every overload (2-, 3-, 4-arity,params,IEnumerable, collection) over all 16 input combinationsWhenStableForWhenTrueForwithScheduler.ImmediateAnd/OrAll five new behavioural tests fail against the previous library code and pass with this change. Full suite: 619 tests green on net8.0, net9.0 and net10.0, built with
TreatWarningsAsErrors=true.