A Golang runtime and compilation backend for Delta Interaction Nets.
at main 206 lines 5.5 kB view raw
1package deltanet 2 3import ( 4 "fmt" 5 "testing" 6) 7 8// TestStringConcat tests concatenating two strings using native functions 9func TestStringConcat(t *testing.T) { 10 net := NewNetwork() 11 12 // Register concat native function 13 net.RegisterNative("concat", func(a interface{}) (interface{}, error) { 14 // This returns a function that captures 'a' (first string) 15 s1, ok := a.(string) 16 if !ok { 17 return nil, fmt.Errorf("concat: first arg must be string, got %T", a) 18 } 19 20 // Return a native function that takes the second argument 21 return func(b interface{}) (interface{}, error) { 22 s2, ok := b.(string) 23 if !ok { 24 return nil, fmt.Errorf("concat: second arg must be string, got %T", b) 25 } 26 return s1 + s2, nil 27 }, nil 28 }) 29 30 // Build net structure for: concat "hello" "world" 31 // This is: (concat "hello") "world" 32 // Structure: Fan(App) where: 33 // Fan.0 -> connects to another Fan(App) for (concat "hello") 34 // Fan.2 -> Data("world") 35 // Fan.1 -> result 36 37 // Inner application: concat "hello" 38 innerFan := net.NewFan() 39 concatNode := net.NewNative("concat") 40 helloData := net.NewData("hello") 41 42 net.Link(innerFan, 0, concatNode, 0) // Function 43 net.Link(innerFan, 2, helloData, 0) // Argument 44 // innerFan.1 is the result of (concat "hello") 45 46 // Outer application: (concat "hello") "world" 47 outerFan := net.NewFan() 48 worldData := net.NewData("world") 49 50 net.Link(outerFan, 0, innerFan, 1) // Function (result of inner app) 51 net.Link(outerFan, 2, worldData, 0) // Argument 52 // outerFan.1 is the final result 53 54 // Connect result to output var 55 output := net.NewVar() 56 net.Link(outerFan, 1, output, 0) 57 58 // Reduce 59 net.ReduceAll() 60 61 // Check result 62 resultNode, resultPort := net.GetLink(output, 0) 63 if resultNode == nil { 64 t.Fatal("Result node is nil") 65 } 66 if resultNode.Type() != NodeTypeData { 67 t.Errorf("Expected result to be Data node, got %v", resultNode.Type()) 68 } 69 70 result := resultNode.GetValue() 71 expected := "helloworld" 72 if result != expected { 73 t.Errorf("Expected %q, got %v", expected, result) 74 } 75 76 t.Logf("Result: %v (port %d)", result, resultPort) 77} 78 79// TestStringLength tests computing the length of a string 80func TestStringLength(t *testing.T) { 81 net := NewNetwork() 82 83 // Register length native function 84 net.RegisterNative("length", func(v interface{}) (interface{}, error) { 85 s, ok := v.(string) 86 if !ok { 87 return nil, fmt.Errorf("length: arg must be string, got %T", v) 88 } 89 return len(s), nil 90 }) 91 92 // Build net structure for: length "hello" 93 // Structure: Fan(App) where: 94 // Fan.0 -> Native("length") 95 // Fan.2 -> Data("hello") 96 // Fan.1 -> result 97 98 fan := net.NewFan() 99 lengthNode := net.NewNative("length") 100 helloData := net.NewData("hello") 101 102 net.Link(fan, 0, lengthNode, 0) // Function 103 net.Link(fan, 2, helloData, 0) // Argument 104 105 // Connect result to output var 106 output := net.NewVar() 107 net.Link(fan, 1, output, 0) 108 109 // Reduce 110 net.ReduceAll() 111 112 // Check result 113 resultNode, resultPort := net.GetLink(output, 0) 114 if resultNode == nil { 115 t.Fatal("Result node is nil") 116 } 117 if resultNode.Type() != NodeTypeData { 118 t.Errorf("Expected result to be Data node, got %v", resultNode.Type()) 119 } 120 121 result := resultNode.GetValue() 122 expected := 5 123 if result != expected { 124 t.Errorf("Expected %d, got %v", expected, result) 125 } 126 127 t.Logf("Result: %v (port %d)", result, resultPort) 128} 129 130// TestConcatLength tests composing concat and length 131// length (concat "hello" "world") should return 10 132func TestConcatLength(t *testing.T) { 133 net := NewNetwork() 134 135 // Register both natives 136 net.RegisterNative("concat", func(a interface{}) (interface{}, error) { 137 s1, ok := a.(string) 138 if !ok { 139 return nil, fmt.Errorf("concat: first arg must be string, got %T", a) 140 } 141 return func(b interface{}) (interface{}, error) { 142 s2, ok := b.(string) 143 if !ok { 144 return nil, fmt.Errorf("concat: second arg must be string, got %T", b) 145 } 146 return s1 + s2, nil 147 }, nil 148 }) 149 150 net.RegisterNative("length", func(v interface{}) (interface{}, error) { 151 s, ok := v.(string) 152 if !ok { 153 return nil, fmt.Errorf("length: arg must be string, got %T", v) 154 } 155 return len(s), nil 156 }) 157 158 // Build: length (concat "hello" "world") 159 // Structure: 160 // 1. Inner: concat "hello" -> partial 161 // 2. Middle: partial "world" -> "helloworld" 162 // 3. Outer: length "helloworld" -> 10 163 164 // Build concat application 165 concatInnerFan := net.NewFan() 166 concatNode := net.NewNative("concat") 167 helloData := net.NewData("hello") 168 net.Link(concatInnerFan, 0, concatNode, 0) 169 net.Link(concatInnerFan, 2, helloData, 0) 170 171 concatOuterFan := net.NewFan() 172 worldData := net.NewData("world") 173 net.Link(concatOuterFan, 0, concatInnerFan, 1) 174 net.Link(concatOuterFan, 2, worldData, 0) 175 // concatOuterFan.1 is "helloworld" 176 177 // Build length application 178 lengthFan := net.NewFan() 179 lengthNode := net.NewNative("length") 180 net.Link(lengthFan, 0, lengthNode, 0) 181 net.Link(lengthFan, 2, concatOuterFan, 1) // Apply to concat result 182 183 // Connect result 184 output := net.NewVar() 185 net.Link(lengthFan, 1, output, 0) 186 187 // Reduce 188 net.ReduceAll() 189 190 // Check result 191 resultNode, _ := net.GetLink(output, 0) 192 if resultNode == nil { 193 t.Fatal("Result node is nil") 194 } 195 if resultNode.Type() != NodeTypeData { 196 t.Errorf("Expected result to be Data node, got %v", resultNode.Type()) 197 } 198 199 result := resultNode.GetValue() 200 expected := 10 201 if result != expected { 202 t.Errorf("Expected %d, got %v", expected, result) 203 } 204 205 t.Logf("length (concat \"hello\" \"world\") = %v", result) 206}