package types import ( "fmt" "reflect" "testing" ) func TestParse(t *testing.T) { i := 1 chk := func(input string, n *Node, expected string) { t.Run(fmt.Sprintf("Parse%d", i), func(t *testing.T) { if n.String() != expected { t.Errorf("Mismatch parsing %s -- Got:\n%s\nExpected:\n%s\n", input, n.String(), expected) } }) i++ } runParseTest := func(input, expected string) { n, err := Parse(input) if err != nil { t.Errorf("Parse error parsing %s\n", input) } chk(input, n, expected) } runSigTest := func(input, expected string) { rem, n := MethodSignature(input, NewNode("AST")) if rem != "" { t.Errorf("Parse error parsing %s. Remainder = %s\n", input, rem) } chk(input, n, expected) } runParseTest(`int`, ` '' - 'int' `) runParseTest(`int`, ` '' - 'int' `) runParseTest(`char*`, ` '' - 'char' - '*' `) runParseTest(`struct Str`, ` '' - 'struct' -- 'Str' `) runParseTest(`uint`, ` '' - 'uint' `) runParseTest(`uind`, ` '' - 'uind' `) runParseTest(`void ()`, ` '' - 'void' - '' `) runParseTest(`void (*)(struct NSRange)`, ` '' - 'void' - '' -- '*' - '' -- '' --- 'struct' ---- 'NSRange' `) runParseTest(`void (* _Nullable)(int)`, ` '' - 'void' - '' -- '*' -- '_Nullable' - '' -- '' --- 'int' `) runParseTest(`NSRange[3]`, ` '' - 'NSRange' - '' -- '3' `) runParseTest(`struct _NSRange[3]`, ` '' - 'struct' -- '_NSRange' - '' -- '3' `) runParseTest(`struct _NSRange (*)(int, char[])`, ` '' - 'struct' -- '_NSRange' - '' -- '*' - '' -- '' --- 'int' -- '' --- 'char' --- '' `) runParseTest(`struct _NSRange (*)(int, char[],NSRange)`, ` '' - 'struct' -- '_NSRange' - '' -- '*' - '' -- '' --- 'int' -- '' --- 'char' --- '' -- '' --- 'NSRange' `) runParseTest(`struct _NSRange (*)(int, char[],struct _NSRange)`, ` '' - 'struct' -- '_NSRange' - '' -- '*' - '' -- '' --- 'int' -- '' --- 'char' --- '' -- '' --- 'struct' ---- '_NSRange' `) runParseTest(`mytype`, ` '' - 'mytype' `) runParseTest(`const int`, ` '' - 'const' - 'int' `) runParseTest(`int[*]`, ` '' - 'int' - '' -- '*' `) runParseTest(`int[3][5]`, ` '' - 'int' - '' -- '3' - '' -- '5' `) runParseTest(`int *`, ` '' - 'int' - '*' `) runParseTest(`int * _Nonnull`, ` '' - 'int' - '*' - '_Nonnull' `) runParseTest(`int **`, ` '' - 'int' - '*' - '*' `) runParseTest(`int *[3]`, ` '' - 'int' - '*' - '' -- '3' `) runParseTest(`int (*)[3]`, ` '' - 'int' - '' -- '*' - '' -- '3' `) runParseTest(`int (*)[*]`, ` '' - 'int' - '' -- '*' - '' -- '*' `) runParseTest(`int *()`, ` '' - 'int' - '*' - '' `) runParseTest(`int *(char*)`, ` '' - 'int' - '*' - '' -- '' --- 'char' --- '*' `) runParseTest(`RANGE *(char*)`, ` '' - 'RANGE' - '*' - '' -- '' --- 'char' --- '*' `) runParseTest(`int (*)(void)`, ` '' - 'int' - '' -- '*' - '' -- '' --- 'void' `) runParseTest(`int (*)(int, unsigned int)`, ` '' - 'int' - '' -- '*' - '' -- '' --- 'int' -- '' --- 'unsigned' --- 'int' `) runParseTest(`int (* _Nullable)(int, unsigned int)`, ` '' - 'int' - '' -- '*' -- '_Nullable' - '' -- '' --- 'int' -- '' --- 'unsigned' --- 'int' `) runParseTest(`int (*const [])(unsigned int, ...)`, ` '' - 'int' - '' -- '*' -- 'const' -- '' - '' -- '' --- 'unsigned' --- 'int' -- '' --- '...' `) runParseTest(`BOOL (* _Nullable)()`, ` '' - 'BOOL' - '' -- '*' -- '_Nullable' - '' `) runParseTest(`BOOL (* _Nullable)(const void * _Nonnull, const void * _Nonnull)`, ` '' - 'BOOL' - '' -- '*' -- '_Nullable' - '' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' `) runParseTest(`BOOL (* _Nullable)(const void * _Nonnull, const void * _Nonnull, int (* _Nullable)(const void * _Nonnull))`, ` '' - 'BOOL' - '' -- '*' -- '_Nullable' - '' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' -- '' --- 'int' --- '' ---- '*' ---- '_Nullable' --- '' ---- '' ----- 'const' ----- 'void' ----- '*' ----- '_Nonnull' `) runParseTest(`BOOL (* _Nullable)(const void * _Nonnull, const void * _Nonnull, NSUInteger (* _Nullable)(const void * _Nonnull))`, ` '' - 'BOOL' - '' -- '*' -- '_Nullable' - '' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' -- '' --- 'const' --- 'void' --- '*' --- '_Nonnull' -- '' --- 'NSUInteger' --- '' ---- '*' ---- '_Nullable' --- '' ---- '' ----- 'const' ----- 'void' ----- '*' ----- '_Nonnull' `) runParseTest(`NSEnumerator * _Nonnull`, ` '' - 'NSEnumerator' - '' -- '' --- 'ObjectType' - '*' - '_Nonnull' `) runParseTest(`NSArray * _Nonnull`, ` '' - 'NSArray' - '' -- '' --- 'NSString' --- '*' - '*' - '_Nonnull' `) runParseTest(`id _Nonnull (^ _Nonnull)(id _Nullable, NSArray * _Nonnull, NSMutableDictionary * _Nullable)`, ` '' - 'id' - '_Nonnull' - '' -- '^' -- '_Nonnull' - '' -- '' --- 'id' --- '_Nullable' -- '' --- 'NSArray' --- '' ---- '' ----- 'NSExpression' ----- '*' --- '*' --- '_Nonnull' -- '' --- 'NSMutableDictionary' --- '*' --- '_Nullable' `) runSigTest(`(void)pressed`, ` '' - '' -- 'void' - 'pressed' `) runSigTest(`(void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes`, ` '' - '' -- 'void' - 'performSelector' - '' -- '' --- 'SEL' -- 'aSelector' - '' -- 'target' -- '' --- 'id' -- 'target' - '' -- 'argument' -- '' --- 'id' -- 'arg' - '' -- 'order' -- '' --- 'NSUInteger' -- 'order' - '' -- 'modes' -- '' --- 'NSArray' --- '' ---- '' ----- 'NSRunLoopMode' --- '*' -- 'modes' `) } func TestFuncs(t *testing.T) { i := 1 var n *Node var err error f := func(input string, actual, expected interface{}) { t.Run(fmt.Sprintf("TestFunc%d", i), func(t *testing.T) { if err != nil { t.Errorf("Error parsing %s\n", input) } if actual == nil && expected == nil { return } if !reflect.DeepEqual(actual, expected) { t.Errorf("Test failed for %s\n", input) } }) i++ } str := "int*" n, err = Parse(str) f(str, n.HasFunc(), false) str = "int (*)(void)" n, err = Parse(str) f(str, n.HasFunc(), true) n, err = nil, nil f("", n.HasFunc(), false) f("", n.IsId(), false) f("", n.IsFunction(), false) f("", n.IsInstancetype(), false) f("", n.IsArray(), false) f("", n.IsStruct(), false) if n.BaseType() != nil { t.Errorf("BaseType() for nil node is not nil\n") } if n.PointsTo() != nil { t.Errorf("PointsTo() for nil node is not nil\n") } if n.ReturnType() != nil { t.Errorf("ReturnType() for nil node is not nil\n") } f("", n.String(), "") f("", n.Qualifiers(), "") f("", n.Annotations(), "") str = "int" n, err = Parse(str) f(str, n.isIndirect("Pointer"), false) if n.ReturnType() != nil { t.Errorf("Return type for non-function is not nil\n") } str = "int*" n, err = Parse(str) f(str, n.isIndirect("Pointer"), true) f(str, n.isIndirect("Array"), false) str = "int* _Nullable" n, err = Parse(str) f(str, n.isIndirect("Pointer"), true) str = "int* _Nonnull" n, err = Parse(str) f(str, n.isIndirect("Pointer"), true) f(str, n.CType(), "int* _Nonnull") f(str, n.CTypeSimplified(), "int*") f(str, n.Annotations(), "_Nonnull") n, err = Parse("int[]") n2, err2 := Parse("int") if err2 != nil { t.Errorf("Cannot parse int") } f(str, n.isIndirect("Pointer"), false) f(str, n.isIndirect("Array"), true) f(str, n.ArrayOf(), n2) f(str, n.CType(), "int[]") f(str, n.CTypeSimplified(), "int[]") str = "const int*[]" n, err = Parse(str) f(str, n.isIndirect("Array"), true) f(str, n.Qualifiers(), "const") str = "int (*)[]" n, err = Parse(str) f(str, n.isIndirect("Array"), true) f(str, n.isIndirect("Pointer"), true) str = "int (* _Nullable * _Nonnull)[]" n, err = Parse(str) f(str, n.isIndirect("Pointer"), true) str = "int (*)(void)" n, err = Parse(str) n2, err2 = Parse("int(void)") if err2 != nil { t.Errorf("Failed to parse int(void)") } f(str, n.PointsTo(), n2) f(str, n.IsPointer(), true) f(str, n.IsFunction(), false) f(str, n.CType(), "int (*)(void)") str = "int *(void)" n, err = Parse(str) f(str, n.IsFunction(), true) n2, _ = Parse("int*") f(str, n.ReturnType(), n2) str = "__kindof NSRange" n, err = Parse(str) f(str, n.IsStruct(), false) f(str, n.IsInstancetype(), false) str = "struct NSRange" n, err = Parse(str) f(str, n.IsStruct(), true) f(str, n.IsFunction(), false) str = "id" n, err = Parse(str) f(str, n.IsId(), true) f(str, n.IsPointer(), true) str = "int * _Nullable * _Nonnull" n, err = Parse(str) n2, _ = Parse("int") f(str, n.BaseType(), n2) str = "__kindof id" n, err = Parse(str) f(str, n.IsId(), true) f(str, n.IsPointer(), true) str = "NSArray *" n, err = Parse(str) f(str, n.CType(), "NSArray *") f(str, n.CTypeSimplified(), "NSArray*") str = "NSRange *(int, NSRange *)" n, err = Parse(str) f(str, n.renameTypedefs("NSRange", "struct NSRange"), true) f(str, n.CType(), "struct NSRange* (int, struct NSRange*)") str = "int*%&#$" n, err = Parse(str) if err == nil { fmt.Printf("%s\n", n.String()) t.Errorf("Parse should have failed for %s\n", str) } var r func(i int) *Node r = func(i int) *Node { n := &Node{} if i > 0 { n.Children = []*Node{r(i - 1)} } return n } n = r(150) str = n.String() if str[len(str)-8:] != "too deep" { fmt.Printf(str[len(str)-8:]) t.Errorf("Deep recursion did not produce an error from (*Node)String()\n") } } func ExampleDebug() { Debug = true dbg("one %s two %d", "string", 15) // Output: one string two 15 Debug = false }