L’utente ha il suo concetto di atomicità, il developer ha il suo…
Utente 1 – Developer 0
image
L’utente crea un nuovo “Calendario”, poco importa cosa sia, diciamo che è un master-detail decisamente classico. Poi, dopo averlo creato, lo organizza come meglio crede e una delle cose che fa è rimuovere le pubblicazioni che non ci saranno, ad esempio quelle del mese di Agosto.
Quello che succede è:
  • Uno degli elementi viene rimosso dalla lista;
  • Tutti gli elementi successivi a quello rimosso vengono modificati per aggiornare, tra le tante, il “numero” dell’Uscita;
Poi… cambia idea e fa un bel sano “Undo” :-)
Quello che per noi sono n operazioni per l’utente corrispondono ad una sola operazione, quindi il livello di atomicità è diverso e naturalmente vince l’utente. Quindi il nostro memento deve supportare una cosa come questa:
[TestMethod]
public void changeTrackingService_atomicOperation_should_set_isChanged_only_on_operation_completed()
{
    var target = new ChangeTrackingService();

    var person = new Person( target );
    var list = new PersonCollection( target );

    using( var actual = target.BeginAtomicOperation() )
    {
        person.Name = "Mauro";
        list.Add( person );
        person.Name = "Mauro Servienti";

        target.IsChanged.ShouldBeFalse();

        actual.Complete();
    }

    target.IsChanged.ShouldBeTrue();
}

[TestMethod]
public void changeTrackingService_using_atomicOperation_should_fully_rollback_using_one_undo()
{
    var target = new ChangeTrackingService();

    var person = new Person( target );
    var list = new PersonCollection( target );

    using( var actual = target.BeginAtomicOperation() )
    {
        person.Name = "Mauro";
        list.Add( person );
        person.Name = "Mauro Servienti";

        actual.Complete();
    }

    target.Undo();

    list.Count.ShouldBeEqualTo( 0 );
    person.Name.ShouldBeEqualTo( String.Empty );
}
e naturalmente questa, un filino più complessa:
[TestMethod]
public void changeTrackingService_using_atomicOperation_redo_should_reapply_all_changes_with_one_pass()
{
    var target = new ChangeTrackingService();

    var person = new Person( target );
    var list = new PersonCollection( target );

    using( var actual = target.BeginAtomicOperation() )
    {
        person.Name = "Mauro";
        list.Add( person );
        person.Name = "Mauro Servienti";

        actual.Complete();
    }

    target.Undo();
    target.Redo();

    list.Count.ShouldBeEqualTo( 1 );
    person.Name.ShouldBeEqualTo( "Mauro Servienti" );
}
Tutti i test passano, e sono stati frutto della mia esternazione :-), il secondo è, per ora, frutto di un hack che mi piace decisamente poco, uno special case interno al motore di Change Tracking.
Utente 1 – Developer 1: palla al centro :-)
Questo però, fortunatamente o meno per voi :-), mi ha ricordato che abbiamo qualcosa in sospeso: date tempo al tempo ;-)
.m