// main.go purpose is to build the interaction layer in between the http endpoints and the http server // Copyright (C) 2019 Emile Hansmaennel // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package structs import ( "fmt" "reflect" "testing" ) // The example below creates a new root node at (0, 0) with the given width. // The width given in this case is 100. func ExampleNewRoot() { root := NewRoot(100) fmt.Printf("%v\n", root) // Output: &{{{0 0} 100} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} } func TestNewRoot(t *testing.T) { type args struct { BoundingBoxWidth float64 } tests := []struct { name string args args want *Node }{ { name: "New root at (0, 0) with a width of 100", args: args{ BoundingBoxWidth: 100, }, want: &Node{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := NewRoot(tt.args.BoundingBoxWidth); !reflect.DeepEqual(got, tt.want) { t.Errorf("NewRoot() = %v, want %v", got, tt.want) } }) } } // The example below creates a new node using the given bounding box func ExampleNewNode() { newNode := NewNode(BoundingBox{ Center: Vec2{ X: 25, Y: 25, }, Width: 50, }) fmt.Printf("%v\n", newNode) // Output: &{{{25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} } func TestNewNode(t *testing.T) { type args struct { bounadry BoundingBox } tests := []struct { name string args args want *Node }{ { name: "Return a new node", args: args{ bounadry: BoundingBox{ Center: Vec2{ X: 3, Y: 15, }, Width: 100, }, }, want: &Node{ Boundary: BoundingBox{ Center: Vec2{ X: 3, Y: 15, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := NewNode(tt.args.bounadry); !reflect.DeepEqual(got, tt.want) { t.Errorf("NewNode() = %v, want %v", got, tt.want) } }) } } // The example below subdivides the node it is called on. // The function inserts four pointers pointing to other nodes into the subtree array representing the quadrants. // // The Code below prints the four subtrees that where generated: func ExampleNode_Subdivide() { root := NewRoot(100) root.Subdivide() for i := 0; i < 4; i++ { fmt.Printf("%v\n", root.Subtrees[i]) } // Output: // &{{{-25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} // &{{{25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} // &{{{-25 -25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} // &{{{25 -25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [ ]} } func TestNode_Subdivide(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } tests := []struct { name string fields fields }{ { name: "Subdivide a tree from [100] to [[50][50][50][50]]", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{ { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := &Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } n.Subdivide() }) } } // Insert a star into a tree. // If the star cannot be inserted (e.g. recursion depth too deep), Insert() returns an error func ExampleNode_Insert() { // Initialize a tree and a star root := NewRoot(100) star := Star2D{ C: Vec2{ X: 12, Y: 34, }, V: Vec2{ X: 0, Y: 0, }, M: 0, } // insert the star into the tree err := root.Insert(star) // handle potential errors if err != nil { panic(err) } fmt.Printf("%v", root) // Output: // Direct insert of (12.000000, 34.000000) // &{{{0 0} 100} {0 0} 0 0 {{12 34} {0 0} 0} [ ]} } // Insert two stars that are very close to each other into the tree. // A problem arises: the tree has to be subdivided so often, that the insert function // raises a recursion depth error func ExampleNode_Insert_error() { // Initialize a tree and two root := NewRoot(100) star1 := Star2D{ C: Vec2{ X: 5, Y: 5, }, V: Vec2{ X: 0, Y: 0, }, M: 0, } star2 := Star2D{ C: Vec2{ X: 5.000000000000001, Y: 5.000000000000001, }, V: Vec2{ X: 0, Y: 0, }, M: 0, } // insert the first star into the tree err := root.Insert(star1) // handle potential errors if err != nil { panic(err) } // insert the second star into the tree err = root.Insert(star2) // handle potential errors if err != nil { panic(err) } // Output: // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Direct insert of (5.000000, 5.000000) // Could not insert star (5.000000, 5.000000) (recursion limit reached) // // Could not insert star (5.000000, 5.000000) (recursion limit reached) } func TestNode_Insert(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } type args struct { star Star2D } tests := []struct { name string fields fields args args wantErr bool }{ { name: "Inserting a single star into a previously empty galaxy", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, }, wantErr: false, }, { name: "Inserting a single star into a galaxy all ready containing a star", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 2, Y: 3, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ star: Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, }, wantErr: false, }, { name: "Inserting a single star onto the boundary limit", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ star: Star2D{ C: Vec2{ X: 25, Y: 25, }, V: Vec2{ X: 0, Y: 0, }, M: 20, }, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := &Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if err := n.Insert(tt.args.star); (err != nil) != tt.wantErr { t.Errorf("Node.Insert() error = %v, wantErr %v", err, tt.wantErr) } }) } } // Generate a tree using the LaTeX forest tree notation // This is a minimal example using only a root node func ExampleNode_GenForestTree() { // Create a new root root := NewRoot(100) root.Star = Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 20, } // generate the tree forestTree := root.GenForestTree(root) fmt.Println(forestTree) // Output: // [10 20[][][][]] } // Generate a tree using the LaTeX forest tree notation. // This is an example displaying a bigger tree. func ExampleNode_GenForestTree_deepTree() { // Create a new root root := NewRoot(100) // Subdivide the root multiple times root.Subdivide() root.Subtrees[1].Subdivide() // Insert a star into the tree root.Subtrees[1].Star = Star2D{ C: Vec2{ X: 20, Y: 30, }, V: Vec2{ X: 0, Y: 0, }, M: 20, } // Generate the tree forestTree := root.GenForestTree(root) fmt.Println(forestTree) // Output: // [[[][][][]][20 30[[][][][]][[][][][]][[][][][]][[][][][]]][[][][][]][[][][][]]] } func TestNode_GenForestTree(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } type args struct { node *Node } tests := []struct { name string fields fields args args want string }{ { name: "Create a forest from a single node with four subnodes", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ node: &Node{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 100, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, want: "[[][][][]]", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if got := n.GenForestTree(tt.args.node); got != tt.want { t.Errorf("Node.GenForestTree() = %v, want %v", got, tt.want) } }) } } // Draws the tree to a pdf using lualatex for building the pdf. // (Luatex is used, because pdflatex apparently cannot handle such deep recursion depths) func ExampleNode_DrawTreeLaTeX() { // create a new root node root := NewRoot(100) // write the LaTeX to out.tex and build the tex using luatex root.DrawTreeLaTeX("out.tex") // Output: } func TestNode_DrawTreeLaTeX(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } type args struct { outpath string } tests := []struct { name string fields fields args args }{ { name: "Draw a tree using latex", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 0, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ outpath: "tree.tex", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } n.DrawTreeLaTeX(tt.args.outpath) }) } } // GetAllStars gets all the stars from a selected tree. // In the example below, an empty node is generated, subdivided and two stars are inserted into it. // Then, a list of all stars (the two that were previously inserted) gets generated and printed. func ExampleNode_GetAllStars() { // Define a new root node root := NewRoot(100) // Subdivide the root root.Subdivide() // Insert two stars into the tree root.Subtrees[1].Star = Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, } root.Subtrees[3].Star = Star2D{ C: Vec2{ X: 30, Y: 40, }, V: Vec2{ X: 0, Y: 0, }, M: 0, } // Get the stars from the tree starsList := root.GetAllStars() // Print all the stars in the list for _, star := range starsList { fmt.Println(star) } // Output: // {{10 20} {0 0} 0} // {{30 40} {0 0} 0} } func TestNode_GetAllStars(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } tests := []struct { name string fields fields want []Star2D }{ { name: "", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 0, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{ { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 30, Y: 40, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 50, Y: 60, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 70, Y: 80, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, }, want: []Star2D{ { C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, { C: Vec2{ X: 30, Y: 40, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, { C: Vec2{ X: 50, Y: 60, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, { C: Vec2{ X: 70, Y: 80, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if got := n.GetAllStars(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Node.GetAllStars() = %v, want %v", got, tt.want) } }) } } // CalcCenterOfMass calculates the center of mass of the node it is called on. // In the example below, the Tree contains two stars with equal mass (10): (20, 30) and (-20, -30). func ExampleNode_CalcCenterOfMass() { root := NewRoot(100) root.Subdivide() star1 := NewStar2D(Vec2{0, 0}, Vec2{0, 0}, 10) star2 := NewStar2D(Vec2{3, 3}, Vec2{0, 0}, 10) // Insert the stars into the tree // There will be no error handling here, we'll assume that everything goes right.. _ = root.Insert(star1) _ = root.Insert(star2) root.CalcTotalMass() centerOfMass := root.CalcCenterOfMass() fmt.Println(centerOfMass) // Output: } func TestNode_CalcCenterOfMass(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } tests := []struct { name string fields fields want Vec2 }{ { name: "Center of mass in between ", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 0, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{ { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 30, Y: 40, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 50, Y: 60, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 70, Y: 80, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, }, want: Vec2{ X: 0, Y: 0, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := &Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if got := n.CalcCenterOfMass(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Node.CalcCenterOfMass() = %v, want %v", got, tt.want) } }) } } // func ExampleNode_CalcTotalMass() { } func TestNode_CalcTotalMass(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } tests := []struct { name string fields fields want float64 }{ { name: "Calculating the total mass two stars", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 0, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{ { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 10, Y: 20, }, V: Vec2{ X: 0, Y: 0, }, M: 42, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: 25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: -25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 30, Y: 40, }, V: Vec2{ X: 0, Y: 0, }, M: 24, }, Subtrees: [4]*Node{}, }, { Boundary: BoundingBox{ Center: Vec2{ X: 25, Y: -25, }, Width: 50, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, }, }, want: 66, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := &Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if got := n.CalcTotalMass(); got != tt.want { t.Errorf("Node.CalcTotalMass() = %v, want %v", got, tt.want) } }) } } // func ExampleNode_CalcAllForces() { } func TestNode_CalcAllForces(t *testing.T) { type fields struct { Boundary BoundingBox CenterOfMass Vec2 TotalMass float64 Depth int Star Star2D Subtrees [4]*Node } type args struct { star Star2D theta float64 } tests := []struct { name string fields fields args args want Vec2 }{ { name: "single star", fields: fields{ Boundary: BoundingBox{ Center: Vec2{ X: 0, Y: 0, }, Width: 0, }, CenterOfMass: Vec2{ X: 0, Y: 0, }, TotalMass: 0, Depth: 0, Star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, Subtrees: [4]*Node{}, }, args: args{ star: Star2D{ C: Vec2{ X: 0, Y: 0, }, V: Vec2{ X: 0, Y: 0, }, M: 0, }, theta: 0, }, want: Vec2{ X: 0, Y: 0, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n := Node{ Boundary: tt.fields.Boundary, CenterOfMass: tt.fields.CenterOfMass, TotalMass: tt.fields.TotalMass, Depth: tt.fields.Depth, Star: tt.fields.Star, Subtrees: tt.fields.Subtrees, } if got := n.CalcAllForces(tt.args.star, tt.args.theta); !reflect.DeepEqual(got, tt.want) { t.Errorf("Node.CalcAllForces() = %v, want %v", got, tt.want) } }) } } // func ExampleCalcForce() { } func TestCalcForce(t *testing.T) { type args struct { s1 Star2D s2 Star2D } tests := []struct { name string args args want Vec2 }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := CalcForce(tt.args.s1, tt.args.s2); !reflect.DeepEqual(got, tt.want) { t.Errorf("CalcForce() = %v, want %v", got, tt.want) } }) } }