blob: 1dff860ea68e401be1b402992b297a0006a3cc60 [file] [log] [blame]
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package demangle
import (
"bufio"
"flag"
"fmt"
"os"
"strings"
"testing"
)
var verbose = flag.Bool("verbose", false, "print each demangle-expected symbol")
const filename = "testdata/demangle-expected"
// A list of exceptions from demangle-expected that we do not handle
// the same as the standard demangler. We keep a list of exceptions
// so that we can use an exact copy of the file. These exceptions are
// all based on different handling of a substitution that refers to a
// template parameter. The standard demangler seems to have a bug in
// which template it uses when a reference or rvalue-reference refers
// to a substitution that resolves to a template parameter.
var exceptions = map[string]bool{
"_ZSt7forwardIRN1x14refobjiteratorINS0_3refINS0_4mime30multipart_section_processorObjIZ15get_body_parserIZZN14mime_processor21make_section_iteratorERKNS2_INS3_10sectionObjENS0_10ptrrefBaseEEEbENKUlvE_clEvEUlSB_bE_ZZNS6_21make_section_iteratorESB_bENKSC_clEvEUlSB_E0_ENS1_INS2_INS0_20outputrefiteratorObjIiEES8_EEEERKSsSB_OT_OT0_EUlmE_NS3_32make_multipart_default_discarderISP_EEEES8_EEEEEOT_RNSt16remove_referenceISW_E4typeE": true,
"_ZN3mdr16in_cached_threadIRZNK4cudr6GPUSet17parallel_for_eachIZN5tns3d20shape_representation7compute7GPUImpl7executeERKNS_1AINS_7ptr_refIKjEELl3ELl3ENS_8c_strideILl1ELl0EEEEERKNS8_INS9_IjEELl4ELl1ESD_EEEUliRKNS1_7ContextERNS7_5StateEE_JSt6vectorISO_SaISO_EEEEEvOT_DpRT0_EUlSP_E_JSt17reference_wrapperISO_EEEENS_12ScopedFutureIDTclfp_spcl7forwardISW_Efp0_EEEEESV_DpOSW_": true,
"_ZNSt9_Any_data9_M_accessIPZN3sel8Selector6SetObjI3FooJPKcMS4_FviEEEEvRT_DpT0_EUlvE_EESA_v": true,
"_ZNSt9_Any_data9_M_accessIPZN13ThreadManager7newTaskIRSt5_BindIFSt7_Mem_fnIM5DiaryFivEEPS5_EEIEEESt6futureINSt9result_ofIFT_DpT0_EE4typeEEOSF_DpOSG_EUlvE_EERSF_v": true,
"_ZNSt9_Any_data9_M_accessIPZN6cereal18polymorphic_detail15getInputBindingINS1_16JSONInputArchiveEEENS1_6detail15InputBindingMapIT_E11SerializersERS7_jEUlPvRSt10unique_ptrIvNS5_12EmptyDeleterIvEEEE0_EESA_v": true,
"_ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v": true,
"_ZNSt9_Any_data9_M_accessIPZN13ThreadManager10futureTaskISt5_BindIFSt7_Mem_fnIM6RunnerFvvEEPS5_EEEEvOT_EUlvE_EERSC_v": true,
}
// For simplicity, this test reads an exact copy of
// libiberty/testsuite/demangle-expected from GCC. See that file for
// the syntax. We ignore all tests that are not --format=gnu-v3 or
// --format=auto with a string starting with _Z.
func TestExpected(t *testing.T) {
f, err := os.Open(filename)
if err != nil {
t.Fatal(err)
}
scanner := bufio.NewScanner(f)
lineno := 1
for {
format, got := getOptLine(t, scanner, &lineno)
if !got {
break
}
report := lineno
input := getLine(t, scanner, &lineno)
expect := getLine(t, scanner, &lineno)
testNoParams := false
skip := false
if len(format) > 0 && format[0] == '-' {
for _, arg := range strings.Fields(format) {
switch arg {
case "--format=gnu-v3":
case "--format=auto":
if !strings.HasPrefix(input, "_Z") {
skip = true
}
case "--no-params":
testNoParams = true
case "--ret-postfix", "--ret-drop":
skip = true
case "--is-v3-ctor", "--is-v3-dtor":
skip = true
default:
if !strings.HasPrefix(arg, "--format=") {
t.Errorf("%s:%d: unrecognized argument %s", filename, report, arg)
}
skip = true
}
}
}
// The libiberty testsuite passes DMGL_TYPES to
// demangle type names, but that doesn't seem useful
// and we don't support it.
if !strings.HasPrefix(input, "_Z") && !strings.HasPrefix(input, "_GLOBAL_") {
skip = true
}
var expectNoParams string
if testNoParams {
expectNoParams = getLine(t, scanner, &lineno)
}
if skip {
continue
}
oneTest(t, report, input, expect, true)
if testNoParams {
oneTest(t, report, input, expectNoParams, false)
}
}
if err := scanner.Err(); err != nil {
t.Error(err)
}
}
// oneTest tests one entry from demangle-expected.
func oneTest(t *testing.T, report int, input, expect string, params bool) {
if *verbose {
fmt.Println(input)
}
exception := exceptions[input]
var s string
var err error
if params {
s, err = ToString(input)
} else {
s, err = ToString(input, NoParams)
}
if err != nil {
if exception {
t.Logf("%s:%d: ignore expected difference: got %q, expected %q", filename, report, err, expect)
return
}
if err != ErrNotMangledName {
if input == expect {
return
}
t.Errorf("%s:%d: %v", filename, report, err)
return
}
s = input
}
if s != expect {
if exception {
t.Logf("%s:%d: ignore expected difference: got %q, expected %q", filename, report, s, expect)
} else {
var a AST
if params {
a, err = ToAST(input)
} else {
a, err = ToAST(input, NoParams)
}
if err != nil {
t.Logf("ToAST error: %v", err)
} else {
t.Logf("\n%#v", a)
}
t.Errorf("%s:%d: params: %t: got %q, expected %q", filename, report, params, s, expect)
}
} else if exception && params {
t.Errorf("%s:%d: unexpected success (input listed in exceptions)", filename, report)
}
}
// getLine reads a line from demangle-expected.
func getLine(t *testing.T, scanner *bufio.Scanner, lineno *int) string {
s, got := getOptLine(t, scanner, lineno)
if !got {
t.Fatalf("%s:%d: unexpected EOF", filename, *lineno)
}
return s
}
// getOptLine reads an optional line from demangle-expected, returning
// false at EOF. It skips comment lines and updates *lineno.
func getOptLine(t *testing.T, scanner *bufio.Scanner, lineno *int) (string, bool) {
for {
if !scanner.Scan() {
return "", false
}
*lineno++
line := scanner.Text()
if !strings.HasPrefix(line, "#") {
return line, true
}
}
}