Skip to content

Commit

Permalink
Fix list patching issue
Browse files Browse the repository at this point in the history
* add more unit tests (diffing)

* add integration tests

* fix demo

* fix

* increase version
  • Loading branch information
JaggerJo authored Jun 25, 2019
1 parent 25adffe commit 269f263
Show file tree
Hide file tree
Showing 4 changed files with 324 additions and 15 deletions.
330 changes: 319 additions & 11 deletions src/Avalonia.FuncUI.UnitTests/VirtualDomTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,148 @@ open System


module VirtualDomTests =
open Avalonia.FuncUI.VirtualDom
open Avalonia.FuncUI.VirtualDom.Delta
open Avalonia.FuncUI
open Avalonia.Controls
open Avalonia.Media

[<Fact>]
let ``integration test 1`` () =
let view =
Views.stackPanel [
Attrs.children [
Views.checkBox [
Attrs.content "1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "2"
Attrs.isChecked true
]
]
]

let view' =
Views.stackPanel [
Attrs.children [
Views.checkBox [
Attrs.content "1"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "2"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "3"
Attrs.isChecked true
]
]
]

let stackpanel = StackPanel()

VirtualDom.Patcher.patch(stackpanel, VirtualDom.Delta.ViewDelta.From view)
Assert.Equal(2, stackpanel.Children.Count)
Assert.Equal("1" :> obj, (stackpanel.Children.[0] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[0] :?> CheckBox).IsChecked)
Assert.Equal("2" :> obj, (stackpanel.Children.[1] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[1] :?> CheckBox).IsChecked)

VirtualDom.Patcher.patch(stackpanel, VirtualDom.Differ.diff(view, view'))
Assert.Equal(3, stackpanel.Children.Count)
Assert.Equal("1" :> obj, (stackpanel.Children.[0] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[0] :?> CheckBox).IsChecked)
Assert.Equal("2" :> obj, (stackpanel.Children.[1] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[1] :?> CheckBox).IsChecked)
Assert.Equal("3" :> obj, (stackpanel.Children.[2] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[2] :?> CheckBox).IsChecked)
()

[<Fact>]
let ``integration test 2`` () =
let view =
Views.stackPanel [
Attrs.children [
Views.checkBox [
Attrs.content "1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "2"
Attrs.isChecked true
]
]
]

let view' =
Views.stackPanel [
Attrs.children [
Views.checkBox [
Attrs.content "new"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "1"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "2"
Attrs.isChecked true
]

]
]

let view'' =
Views.stackPanel [
Attrs.children [
Views.checkBox [
Attrs.content "new"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "1"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "2"
Attrs.isChecked false
]

]
]

let stackpanel = StackPanel()

VirtualDom.Patcher.patch(stackpanel, VirtualDom.Delta.ViewDelta.From view)
Assert.Equal(2, stackpanel.Children.Count)
Assert.Equal("1" :> obj, (stackpanel.Children.[0] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[0] :?> CheckBox).IsChecked)
Assert.Equal("2" :> obj, (stackpanel.Children.[1] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[1] :?> CheckBox).IsChecked)

VirtualDom.Patcher.patch(stackpanel, VirtualDom.Differ.diff(view, view'))
Assert.Equal(3, stackpanel.Children.Count)
Assert.Equal("new" :> obj, (stackpanel.Children.[0] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[0] :?> CheckBox).IsChecked)
Assert.Equal("1" :> obj, (stackpanel.Children.[1] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[1] :?> CheckBox).IsChecked)
Assert.Equal("2" :> obj, (stackpanel.Children.[2] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[2] :?> CheckBox).IsChecked)

VirtualDom.Patcher.patch(stackpanel, VirtualDom.Differ.diff(view', view''))
Assert.Equal(3, stackpanel.Children.Count)
Assert.Equal("new" :> obj, (stackpanel.Children.[0] :?> CheckBox).Content)
Assert.Equal(Nullable(true), (stackpanel.Children.[0] :?> CheckBox).IsChecked)
Assert.Equal("1" :> obj, (stackpanel.Children.[1] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[1] :?> CheckBox).IsChecked)
Assert.Equal("2" :> obj, (stackpanel.Children.[2] :?> CheckBox).Content)
Assert.Equal(Nullable(false), (stackpanel.Children.[2] :?> CheckBox).IsChecked)
()

module DifferTests =
open Avalonia.FuncUI.VirtualDom
open Avalonia.FuncUI.VirtualDom.Delta
open Avalonia.FuncUI
open Avalonia.Controls
open Avalonia.Media

[<Fact>]
let ``Diff Properties`` () =
Expand Down Expand Up @@ -217,12 +352,185 @@ module VirtualDomTests =
// just to make sure the types are actually comparable
Assert.True(not (delta <> result))

[<Fact>]
let ``Diff Content Multiple (insert iten into homogenous list - tail)`` () =
let last =
Views.stackPanel [
Attrs.orientation Orientation.Horizontal
Attrs.children [
Views.checkBox [
Attrs.content "some text 1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "some text 2"
Attrs.isChecked false
]
]
]

let next =
Views.stackPanel [
Attrs.orientation Orientation.Vertical
Attrs.children [
Views.checkBox [
Attrs.content "some text [new]"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "some text 1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "some text 2"
Attrs.isChecked false
]
]
]

let delta =
{
ViewType = typeof<StackPanel>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Orientation"
Value = Some (Orientation.Vertical :> obj)
};
AttrDelta.ContentDelta {
Name = "Children"
Content = ViewContentDelta.Multiple [
{
ViewType = typeof<CheckBox>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Content"
Value = Some ("some text [new]" :> obj)
};
AttrDelta.PropertyDelta {
Name = "IsChecked"
Value = Some (false :> obj)
};
]
};
{
ViewType = typeof<CheckBox>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Content"
Value = Some ("some text 1" :> obj)
};
AttrDelta.PropertyDelta {
Name = "IsChecked"
Value = Some (true :> obj)
};
]
};
{
ViewType = typeof<CheckBox>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Content"
Value = Some ("some text 2" :> obj)
};
AttrDelta.PropertyDelta {
Name = "IsChecked"
Value = Some (false :> obj)
};
]
};
]
};
]
}

let result = Differ.diff(last, next)

Assert.Equal(delta, result)

// just to make sure the types are actually comparable
Assert.True(not (delta <> result))

[<Fact>]
let ``Diff Content Multiple (insert iten into homogenous list - head)`` () =
let last =
Views.stackPanel [
Attrs.orientation Orientation.Horizontal
Attrs.children [
Views.checkBox [
Attrs.content "some text 1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "some text 2"
Attrs.isChecked false
]
]
]

let next =
Views.stackPanel [
Attrs.orientation Orientation.Vertical
Attrs.children [
Views.checkBox [
Attrs.content "some text 1"
Attrs.isChecked true
]
Views.checkBox [
Attrs.content "some text 2"
Attrs.isChecked false
]
Views.checkBox [
Attrs.content "some text [new]"
Attrs.isChecked true
]
]
]

let delta =
{
ViewType = typeof<StackPanel>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Orientation"
Value = Some (Orientation.Vertical :> obj)
};
AttrDelta.ContentDelta {
Name = "Children"
Content = ViewContentDelta.Multiple [
{
ViewType = typeof<CheckBox>
Attrs = []
};
{
ViewType = typeof<CheckBox>
Attrs = []
};
{
ViewType = typeof<CheckBox>
Attrs = [
AttrDelta.PropertyDelta {
Name = "Content"
Value = Some ("some text [new]" :> obj)
};
AttrDelta.PropertyDelta {
Name = "IsChecked"
Value = Some (true :> obj)
};
]
};
]
};
]
}

let result = Differ.diff(last, next)

Assert.Equal(delta, result)

// just to make sure the types are actually comparable
Assert.True(not (delta <> result))

module PatcherTests =
open Avalonia.FuncUI.VirtualDom
open Avalonia.FuncUI.VirtualDom.Delta
open Avalonia.FuncUI
open Avalonia.Controls
open Avalonia.Media

[<Fact>]
let ``Patch Properties`` () =
Expand Down Expand Up @@ -360,4 +668,4 @@ module VirtualDomTests =

Assert.IsType(typeof<Button>, stackpanel.Children.[2])
let button = stackpanel.Children.[2] :?> Button
Assert.Equal(SolidColorBrush.Parse("green").ToImmutable(), button.Background)
Assert.Equal(SolidColorBrush.Parse("green").ToImmutable(), button.Background)
2 changes: 1 addition & 1 deletion src/Avalonia.FuncUI/Avalonia.FuncUI.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>0.1.0</Version>
<Version>0.1.1</Version>
<Authors>JaggerJo</Authors>
<Product>JaggerJo.Avalonia.FuncUI</Product>
<PackageProjectUrl>https://github.com/JaggerJo/Avalonia.FuncUI</PackageProjectUrl>
Expand Down
3 changes: 2 additions & 1 deletion src/Avalonia.FuncUI/Core/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ module rec Types =
this.Name.GetHashCode()

override this.Equals other =
this.GetHashCode() = other.GetHashCode()
// TODO: find a better way to do this
false // always set event

type ContentAttr =
{
Expand Down
4 changes: 2 additions & 2 deletions src/Examples/Inspector/Views.fs
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,11 @@ module ElementsView =
| ElementView.Event event ->
match filter.FilterText with
| Some some -> filter.IncludeEvents && event.Name.StartsWith some
| None -> filter.IncludeProperties
| None -> filter.IncludeEvents
| ElementView.Control control ->
match filter.FilterText with
| Some some -> filter.IncludeControls && control.Name.StartsWith some
| None -> filter.IncludeProperties
| None -> filter.IncludeControls


let view (state: State) (filter: FilterView.State) dispatch : View =
Expand Down

0 comments on commit 269f263

Please sign in to comment.