github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/dbc/parser_test.go (about)

     1  package dbc
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  	"text/scanner"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"gotest.tools/v3/assert"
    12  )
    13  
    14  func shouldUpdateGoldenFiles() bool {
    15  	return os.Getenv("GOLDEN") == "true"
    16  }
    17  
    18  func TestParse_ExampleDBC(t *testing.T) {
    19  	const inputFile = "../../testdata/dbc/example/example.dbc"
    20  	const goldenFile = "../../testdata/dbc/example/example.dbc.golden"
    21  	data, err := ioutil.ReadFile(inputFile)
    22  	assert.NilError(t, err)
    23  	p := NewParser(inputFile, data)
    24  	assert.NilError(t, p.Parse())
    25  	if shouldUpdateGoldenFiles() {
    26  		assert.NilError(t, ioutil.WriteFile(goldenFile, []byte(dump(p.Defs())), 0600))
    27  	}
    28  	goldenFileData, err := ioutil.ReadFile(goldenFile)
    29  	assert.NilError(t, err)
    30  	assert.Equal(t, string(goldenFileData), dump(p.Defs()))
    31  }
    32  
    33  func TestParser_Parse(t *testing.T) {
    34  	for _, tt := range []struct {
    35  		name string
    36  		text string
    37  		defs []Def
    38  	}{
    39  		{
    40  			name: "version.dbc",
    41  			text: `VERSION "foo"`,
    42  			defs: []Def{
    43  				&VersionDef{
    44  					Pos: scanner.Position{
    45  						Filename: "version.dbc",
    46  						Line:     1,
    47  						Column:   1,
    48  					},
    49  					Version: "foo",
    50  				},
    51  			},
    52  		},
    53  
    54  		{
    55  			name: "multiple_version.dbc",
    56  			text: strings.Join([]string{
    57  				`VERSION "foo"`,
    58  				`VERSION "bar"`,
    59  			}, "\n"),
    60  			defs: []Def{
    61  				&VersionDef{
    62  					Pos: scanner.Position{
    63  						Filename: "multiple_version.dbc",
    64  						Line:     1,
    65  						Column:   1,
    66  					},
    67  					Version: "foo",
    68  				},
    69  				&VersionDef{
    70  					Pos: scanner.Position{
    71  						Filename: "multiple_version.dbc",
    72  						Line:     2,
    73  						Column:   1,
    74  						Offset:   14,
    75  					},
    76  					Version: "bar",
    77  				},
    78  			},
    79  		},
    80  
    81  		{
    82  			name: "no_bus_speed.dbc",
    83  			text: `BS_:`,
    84  			defs: []Def{
    85  				&BitTimingDef{
    86  					Pos: scanner.Position{
    87  						Filename: "no_bus_speed.dbc",
    88  						Line:     1,
    89  						Column:   1,
    90  					},
    91  				},
    92  			},
    93  		},
    94  
    95  		{
    96  			name: "bus_speed.dbc",
    97  			text: `BS_: 250000`,
    98  			defs: []Def{
    99  				&BitTimingDef{
   100  					Pos: scanner.Position{
   101  						Filename: "bus_speed.dbc",
   102  						Line:     1,
   103  						Column:   1,
   104  					},
   105  					BaudRate: 250000,
   106  				},
   107  			},
   108  		},
   109  
   110  		{
   111  			name: "symbols.dbc",
   112  			text: strings.Join([]string{
   113  				"NS_ :",
   114  				"NS_DESC_",
   115  				"CM_",
   116  				"BA_DEF_",
   117  				"BA_",
   118  				"VAL_",
   119  			}, "\n\t"),
   120  			defs: []Def{
   121  				&NewSymbolsDef{
   122  					Pos: scanner.Position{
   123  						Filename: "symbols.dbc",
   124  						Line:     1,
   125  						Column:   1,
   126  					},
   127  					Symbols: []Keyword{
   128  						"NS_DESC_",
   129  						"CM_",
   130  						"BA_DEF_",
   131  						"BA_",
   132  						"VAL_",
   133  					},
   134  				},
   135  			},
   136  		},
   137  
   138  		{
   139  			name: "standard_message.dbc",
   140  			text: "BO_ 804 CRUISE: 8 PCM",
   141  			defs: []Def{
   142  				&MessageDef{
   143  					Pos: scanner.Position{
   144  						Filename: "standard_message.dbc",
   145  						Line:     1,
   146  						Column:   1,
   147  					},
   148  					Name:        "CRUISE",
   149  					MessageID:   804,
   150  					Size:        8,
   151  					Transmitter: "PCM",
   152  				},
   153  			},
   154  		},
   155  
   156  		{
   157  			name: "extended_message.dbc",
   158  			text: "BO_ 2566857412 BMS2_4: 8 Vector__XXX",
   159  			defs: []Def{
   160  				&MessageDef{
   161  					Pos: scanner.Position{
   162  						Filename: "extended_message.dbc",
   163  						Line:     1,
   164  						Column:   1,
   165  					},
   166  					Name:        "BMS2_4",
   167  					MessageID:   2566857412,
   168  					Size:        8,
   169  					Transmitter: "Vector__XXX",
   170  				},
   171  			},
   172  		},
   173  
   174  		{
   175  			name: "signal.dbc",
   176  			text: `SG_ CellTempLowest : 32|8@0+ (1,-40) [-40|215] "C" Vector__XXX`,
   177  			defs: []Def{
   178  				&SignalDef{
   179  					Pos: scanner.Position{
   180  						Filename: "signal.dbc",
   181  						Line:     1,
   182  						Column:   1,
   183  					},
   184  					Name:        "CellTempLowest",
   185  					StartBit:    32,
   186  					Size:        8,
   187  					IsBigEndian: true,
   188  					Factor:      1,
   189  					Offset:      -40,
   190  					Minimum:     -40,
   191  					Maximum:     215,
   192  					Unit:        "C",
   193  					Receivers:   []Identifier{"Vector__XXX"},
   194  				},
   195  			},
   196  		},
   197  
   198  		{
   199  			name: "multiplexer_signal.dbc",
   200  			text: `SG_ TestSignal M : 56|8@1+ (0.001,0) [0|0.255] "l/mm" XXX`,
   201  			defs: []Def{
   202  				&SignalDef{
   203  					Pos: scanner.Position{
   204  						Filename: "multiplexer_signal.dbc",
   205  						Line:     1,
   206  						Column:   1,
   207  					},
   208  					Name:                "TestSignal",
   209  					StartBit:            56,
   210  					Size:                8,
   211  					Factor:              0.001,
   212  					Offset:              0,
   213  					Minimum:             0,
   214  					Maximum:             0.255,
   215  					Unit:                "l/mm",
   216  					Receivers:           []Identifier{"XXX"},
   217  					IsMultiplexerSwitch: true,
   218  				},
   219  			},
   220  		},
   221  
   222  		{
   223  			name: "multiplexed_signal.dbc",
   224  			text: `SG_ TestSignal m2 : 56|8@1+ (0.001,0) [0|0.255] "l/mm" XXX`,
   225  			defs: []Def{
   226  				&SignalDef{
   227  					Pos: scanner.Position{
   228  						Filename: "multiplexed_signal.dbc",
   229  						Line:     1,
   230  						Column:   1,
   231  					},
   232  					Name:              "TestSignal",
   233  					StartBit:          56,
   234  					Size:              8,
   235  					Factor:            0.001,
   236  					Offset:            0,
   237  					Minimum:           0,
   238  					Maximum:           0.255,
   239  					Unit:              "l/mm",
   240  					Receivers:         []Identifier{"XXX"},
   241  					IsMultiplexed:     true,
   242  					MultiplexerSwitch: 2,
   243  				},
   244  			},
   245  		},
   246  
   247  		{
   248  			name: "comment.dbc",
   249  			text: `CM_ "comment";`,
   250  			defs: []Def{
   251  				&CommentDef{
   252  					Pos: scanner.Position{
   253  						Filename: "comment.dbc",
   254  						Line:     1,
   255  						Column:   1,
   256  					},
   257  					Comment: "comment",
   258  				},
   259  			},
   260  		},
   261  
   262  		{
   263  			name: "node_comment.dbc",
   264  			text: `CM_ BU_ NodeName "node comment";`,
   265  			defs: []Def{
   266  				&CommentDef{
   267  					Pos: scanner.Position{
   268  						Filename: "node_comment.dbc",
   269  						Line:     1,
   270  						Column:   1,
   271  					},
   272  					ObjectType: ObjectTypeNetworkNode,
   273  					NodeName:   "NodeName",
   274  					Comment:    "node comment",
   275  				},
   276  			},
   277  		},
   278  
   279  		{
   280  			name: "message_comment.dbc",
   281  			text: `CM_ BO_ 1234 "message comment";`,
   282  			defs: []Def{
   283  				&CommentDef{
   284  					Pos: scanner.Position{
   285  						Filename: "message_comment.dbc",
   286  						Line:     1,
   287  						Column:   1,
   288  					},
   289  					ObjectType: ObjectTypeMessage,
   290  					MessageID:  1234,
   291  					Comment:    "message comment",
   292  				},
   293  			},
   294  		},
   295  
   296  		{
   297  			name: "signal_comment.dbc",
   298  			text: `CM_ SG_ 1234 SignalName "signal comment";`,
   299  			defs: []Def{
   300  				&CommentDef{
   301  					Pos: scanner.Position{
   302  						Filename: "signal_comment.dbc",
   303  						Line:     1,
   304  						Column:   1,
   305  					},
   306  					ObjectType: ObjectTypeSignal,
   307  					MessageID:  1234,
   308  					SignalName: "SignalName",
   309  					Comment:    "signal comment",
   310  				},
   311  			},
   312  		},
   313  
   314  		{
   315  			name: "int_attribute_definition.dbc",
   316  			text: `BA_DEF_ "AttributeName" INT 5 10;`,
   317  			defs: []Def{
   318  				&AttributeDef{
   319  					Pos: scanner.Position{
   320  						Filename: "int_attribute_definition.dbc",
   321  						Line:     1,
   322  						Column:   1,
   323  					},
   324  					Name:       "AttributeName",
   325  					Type:       AttributeValueTypeInt,
   326  					MinimumInt: 5,
   327  					MaximumInt: 10,
   328  				},
   329  			},
   330  		},
   331  
   332  		{
   333  			name: "int_attribute_definition_no_min_or_max.dbc",
   334  			text: `BA_DEF_ "AttributeName" INT;`,
   335  			defs: []Def{
   336  				&AttributeDef{
   337  					Pos: scanner.Position{
   338  						Filename: "int_attribute_definition_no_min_or_max.dbc",
   339  						Line:     1,
   340  						Column:   1,
   341  					},
   342  					Name: "AttributeName",
   343  					Type: AttributeValueTypeInt,
   344  				},
   345  			},
   346  		},
   347  
   348  		{
   349  			name: "float_attribute_definition.dbc",
   350  			text: `BA_DEF_ "AttributeName" FLOAT 0.5 1.5;`,
   351  			defs: []Def{
   352  				&AttributeDef{
   353  					Pos: scanner.Position{
   354  						Filename: "float_attribute_definition.dbc",
   355  						Line:     1,
   356  						Column:   1,
   357  					},
   358  					Name:         "AttributeName",
   359  					Type:         AttributeValueTypeFloat,
   360  					MinimumFloat: 0.5,
   361  					MaximumFloat: 1.5,
   362  				},
   363  			},
   364  		},
   365  
   366  		{
   367  			name: "float_attribute_definition_no_min_or_max.dbc",
   368  			text: `BA_DEF_ "AttributeName" FLOAT;`,
   369  			defs: []Def{
   370  				&AttributeDef{
   371  					Pos: scanner.Position{
   372  						Filename: "float_attribute_definition_no_min_or_max.dbc",
   373  						Line:     1,
   374  						Column:   1,
   375  					},
   376  					Name: "AttributeName",
   377  					Type: AttributeValueTypeFloat,
   378  				},
   379  			},
   380  		},
   381  
   382  		{
   383  			name: "string_attribute.dbc",
   384  			text: `BA_DEF_ "AttributeName" STRING;`,
   385  			defs: []Def{
   386  				&AttributeDef{
   387  					Pos: scanner.Position{
   388  						Filename: "string_attribute.dbc",
   389  						Line:     1,
   390  						Column:   1,
   391  					},
   392  					Name: "AttributeName",
   393  					Type: AttributeValueTypeString,
   394  				},
   395  			},
   396  		},
   397  
   398  		{
   399  			name: "enum_attribute.dbc",
   400  			text: `BA_DEF_ "AttributeName" ENUM "value1","value2";`,
   401  			defs: []Def{
   402  				&AttributeDef{
   403  					Pos: scanner.Position{
   404  						Filename: "enum_attribute.dbc",
   405  						Line:     1,
   406  						Column:   1,
   407  					},
   408  					Name:       "AttributeName",
   409  					Type:       AttributeValueTypeEnum,
   410  					EnumValues: []string{"value1", "value2"},
   411  				},
   412  			},
   413  		},
   414  
   415  		{
   416  			name: "enum_attribute_for_messages.dbc",
   417  			text: `BA_DEF_ BO_  "VFrameFormat" ENUM  "StandardCAN","ExtendedCAN","reserved","J1939PG";`,
   418  			defs: []Def{
   419  				&AttributeDef{
   420  					Pos: scanner.Position{
   421  						Filename: "enum_attribute_for_messages.dbc",
   422  						Line:     1,
   423  						Column:   1,
   424  					},
   425  					Name:       "VFrameFormat",
   426  					ObjectType: ObjectTypeMessage,
   427  					Type:       AttributeValueTypeEnum,
   428  					EnumValues: []string{"StandardCAN", "ExtendedCAN", "reserved", "J1939PG"},
   429  				},
   430  			},
   431  		},
   432  
   433  		{
   434  			name: "attribute_default_string.dbc",
   435  			text: strings.Join([]string{
   436  				`BA_DEF_ "Foo" STRING;`,
   437  				`BA_DEF_DEF_ "Foo" "string value";`,
   438  			}, "\n"),
   439  			defs: []Def{
   440  				&AttributeDef{
   441  					Pos: scanner.Position{
   442  						Filename: "attribute_default_string.dbc",
   443  						Line:     1,
   444  						Column:   1,
   445  					},
   446  					Name: "Foo",
   447  					Type: AttributeValueTypeString,
   448  				},
   449  				&AttributeDefaultValueDef{
   450  					Pos: scanner.Position{
   451  						Filename: "attribute_default_string.dbc",
   452  						Line:     2,
   453  						Column:   1,
   454  						Offset:   22,
   455  					},
   456  					AttributeName:      "Foo",
   457  					DefaultStringValue: "string value",
   458  				},
   459  			},
   460  		},
   461  
   462  		{
   463  			name: "attribute_default_int.dbc",
   464  			text: strings.Join([]string{
   465  				`BA_DEF_ "Foo" INT 0 200;`,
   466  				`BA_DEF_DEF_ "Foo" 100;`,
   467  			}, "\n"),
   468  			defs: []Def{
   469  				&AttributeDef{
   470  					Pos: scanner.Position{
   471  						Filename: "attribute_default_int.dbc",
   472  						Line:     1,
   473  						Column:   1,
   474  					},
   475  					Name:       "Foo",
   476  					Type:       AttributeValueTypeInt,
   477  					MinimumInt: 0,
   478  					MaximumInt: 200,
   479  				},
   480  				&AttributeDefaultValueDef{
   481  					Pos: scanner.Position{
   482  						Filename: "attribute_default_int.dbc",
   483  						Line:     2,
   484  						Column:   1,
   485  						Offset:   25,
   486  					},
   487  					AttributeName:   "Foo",
   488  					DefaultIntValue: 100,
   489  				},
   490  			},
   491  		},
   492  
   493  		{
   494  			name: "attribute_default_float.dbc",
   495  			text: strings.Join([]string{
   496  				`BA_DEF_ "Foo" FLOAT 0.5 200.5;`,
   497  				`BA_DEF_DEF_ "Foo" 100.5;`,
   498  			}, "\n"),
   499  			defs: []Def{
   500  				&AttributeDef{
   501  					Pos: scanner.Position{
   502  						Filename: "attribute_default_float.dbc",
   503  						Line:     1,
   504  						Column:   1,
   505  					},
   506  					Name:         "Foo",
   507  					Type:         AttributeValueTypeFloat,
   508  					MinimumFloat: 0.5,
   509  					MaximumFloat: 200.5,
   510  				},
   511  				&AttributeDefaultValueDef{
   512  					Pos: scanner.Position{
   513  						Filename: "attribute_default_float.dbc",
   514  						Line:     2,
   515  						Column:   1,
   516  						Offset:   31,
   517  					},
   518  					AttributeName:     "Foo",
   519  					DefaultFloatValue: 100.5,
   520  				},
   521  			},
   522  		},
   523  
   524  		{
   525  			name: "attribute_value.dbc",
   526  			text: strings.Join([]string{
   527  				`BA_DEF_ "Foo" FLOAT;`,
   528  				`BA_ "Foo" 100.5;`,
   529  			}, "\n"),
   530  			defs: []Def{
   531  				&AttributeDef{
   532  					Pos: scanner.Position{
   533  						Filename: "attribute_value.dbc",
   534  						Line:     1,
   535  						Column:   1,
   536  					},
   537  					Name: "Foo",
   538  					Type: AttributeValueTypeFloat,
   539  				},
   540  				&AttributeValueForObjectDef{
   541  					Pos: scanner.Position{
   542  						Filename: "attribute_value.dbc",
   543  						Line:     2,
   544  						Column:   1,
   545  						Offset:   21,
   546  					},
   547  					AttributeName: "Foo",
   548  					FloatValue:    100.5,
   549  				},
   550  			},
   551  		},
   552  
   553  		{
   554  			name: "negative_attribute_value.dbc",
   555  			text: strings.Join([]string{
   556  				`BA_DEF_ "Foo" INT;`,
   557  				`BA_ "Foo" -100;`,
   558  			}, "\n"),
   559  			defs: []Def{
   560  				&AttributeDef{
   561  					Pos: scanner.Position{
   562  						Filename: "negative_attribute_value.dbc",
   563  						Line:     1,
   564  						Column:   1,
   565  					},
   566  					Name: "Foo",
   567  					Type: AttributeValueTypeInt,
   568  				},
   569  				&AttributeValueForObjectDef{
   570  					Pos: scanner.Position{
   571  						Filename: "negative_attribute_value.dbc",
   572  						Line:     2,
   573  						Column:   1,
   574  						Offset:   19,
   575  					},
   576  					AttributeName: "Foo",
   577  					IntValue:      -100,
   578  				},
   579  			},
   580  		},
   581  
   582  		{
   583  			name: "node_attribute_value.dbc",
   584  			text: strings.Join([]string{
   585  				`BA_DEF_ "Foo" INT;`,
   586  				`BA_ "Foo" BU_ TestNode 100;`,
   587  			}, "\n"),
   588  			defs: []Def{
   589  				&AttributeDef{
   590  					Pos: scanner.Position{
   591  						Filename: "node_attribute_value.dbc",
   592  						Line:     1,
   593  						Column:   1,
   594  					},
   595  					Name: "Foo",
   596  					Type: AttributeValueTypeInt,
   597  				},
   598  				&AttributeValueForObjectDef{
   599  					Pos: scanner.Position{
   600  						Filename: "node_attribute_value.dbc",
   601  						Line:     2,
   602  						Column:   1,
   603  						Offset:   19,
   604  					},
   605  					AttributeName: "Foo",
   606  					ObjectType:    ObjectTypeNetworkNode,
   607  					NodeName:      "TestNode",
   608  					IntValue:      100,
   609  				},
   610  			},
   611  		},
   612  
   613  		{
   614  			name: "message_attribute_value.dbc",
   615  			text: strings.Join([]string{
   616  				`BA_DEF_ "Foo" STRING;`,
   617  				`BA_ "Foo" BO_ 1234 "string value";`,
   618  			}, "\n"),
   619  			defs: []Def{
   620  				&AttributeDef{
   621  					Pos: scanner.Position{
   622  						Filename: "message_attribute_value.dbc",
   623  						Line:     1,
   624  						Column:   1,
   625  					},
   626  					Name: "Foo",
   627  					Type: AttributeValueTypeString,
   628  				},
   629  				&AttributeValueForObjectDef{
   630  					Pos: scanner.Position{
   631  						Filename: "message_attribute_value.dbc",
   632  						Line:     2,
   633  						Column:   1,
   634  						Offset:   22,
   635  					},
   636  					AttributeName: "Foo",
   637  					ObjectType:    ObjectTypeMessage,
   638  					MessageID:     1234,
   639  					StringValue:   "string value",
   640  				},
   641  			},
   642  		},
   643  
   644  		{
   645  			name: "signal_attribute_value.dbc",
   646  			text: strings.Join([]string{
   647  				`BA_DEF_ "Foo" STRING;`,
   648  				`BA_ "Foo" SG_ 1234 SignalName "string value";`,
   649  			}, "\n"),
   650  			defs: []Def{
   651  				&AttributeDef{
   652  					Pos: scanner.Position{
   653  						Filename: "signal_attribute_value.dbc",
   654  						Line:     1,
   655  						Column:   1,
   656  					},
   657  					Name: "Foo",
   658  					Type: AttributeValueTypeString,
   659  				},
   660  				&AttributeValueForObjectDef{
   661  					Pos: scanner.Position{
   662  						Filename: "signal_attribute_value.dbc",
   663  						Line:     2,
   664  						Column:   1,
   665  						Offset:   22,
   666  					},
   667  					AttributeName: "Foo",
   668  					ObjectType:    ObjectTypeSignal,
   669  					MessageID:     1234,
   670  					SignalName:    "SignalName",
   671  					StringValue:   "string value",
   672  				},
   673  			},
   674  		},
   675  
   676  		{
   677  			name: "enum_attribute_value_by_index.dbc",
   678  			text: strings.Join([]string{
   679  				`BA_DEF_ BO_  "VFrameFormat" ENUM  "StandardCAN","ExtendedCAN","reserved","J1939PG";`,
   680  				`BA_ "VFrameFormat" BO_ 1234 3;`,
   681  			}, "\n"),
   682  			defs: []Def{
   683  				&AttributeDef{
   684  					Pos: scanner.Position{
   685  						Filename: "enum_attribute_value_by_index.dbc",
   686  						Line:     1,
   687  						Column:   1,
   688  					},
   689  					Name:       "VFrameFormat",
   690  					ObjectType: ObjectTypeMessage,
   691  					Type:       AttributeValueTypeEnum,
   692  					EnumValues: []string{"StandardCAN", "ExtendedCAN", "reserved", "J1939PG"},
   693  				},
   694  				&AttributeValueForObjectDef{
   695  					Pos: scanner.Position{
   696  						Filename: "enum_attribute_value_by_index.dbc",
   697  						Line:     2,
   698  						Column:   1,
   699  						Offset:   84,
   700  					},
   701  					AttributeName: "VFrameFormat",
   702  					ObjectType:    ObjectTypeMessage,
   703  					MessageID:     1234,
   704  					StringValue:   "J1939PG",
   705  				},
   706  			},
   707  		},
   708  
   709  		{
   710  			name: "value_descriptions_for_signal.dbc",
   711  			text: `VAL_ 3 StW_AnglSens_Id 2 "MUST" 0 "PSBL" 1 "SELF";`,
   712  			defs: []Def{
   713  				&ValueDescriptionsDef{
   714  					Pos: scanner.Position{
   715  						Filename: "value_descriptions_for_signal.dbc",
   716  						Line:     1,
   717  						Column:   1,
   718  					},
   719  					ObjectType: ObjectTypeSignal,
   720  					MessageID:  3,
   721  					SignalName: "StW_AnglSens_Id",
   722  					ValueDescriptions: []ValueDescriptionDef{
   723  						{
   724  							Pos: scanner.Position{
   725  								Filename: "value_descriptions_for_signal.dbc",
   726  								Line:     1,
   727  								Column:   24,
   728  								Offset:   23,
   729  							},
   730  							Value:       2,
   731  							Description: "MUST",
   732  						},
   733  						{
   734  							Pos: scanner.Position{
   735  								Filename: "value_descriptions_for_signal.dbc",
   736  								Line:     1,
   737  								Column:   33,
   738  								Offset:   32,
   739  							},
   740  							Value:       0,
   741  							Description: "PSBL",
   742  						},
   743  						{
   744  							Pos: scanner.Position{
   745  								Filename: "value_descriptions_for_signal.dbc",
   746  								Line:     1,
   747  								Column:   42,
   748  								Offset:   41,
   749  							},
   750  							Value:       1,
   751  							Description: "SELF",
   752  						},
   753  					},
   754  				},
   755  			},
   756  		},
   757  
   758  		{
   759  			name: "value_table.dbc",
   760  			text: `VAL_TABLE_ DI_gear 7 "DI_GEAR_SNA" 4 "DI_GEAR_D";`,
   761  			defs: []Def{
   762  				&ValueTableDef{
   763  					Pos: scanner.Position{
   764  						Filename: "value_table.dbc",
   765  						Line:     1,
   766  						Column:   1,
   767  					},
   768  					TableName: "DI_gear",
   769  					ValueDescriptions: []ValueDescriptionDef{
   770  						{
   771  							Pos: scanner.Position{
   772  								Filename: "value_table.dbc",
   773  								Line:     1,
   774  								Column:   20,
   775  								Offset:   19,
   776  							},
   777  							Value:       7,
   778  							Description: "DI_GEAR_SNA",
   779  						},
   780  						{
   781  							Pos: scanner.Position{
   782  								Filename: "value_table.dbc",
   783  								Line:     1,
   784  								Column:   36,
   785  								Offset:   35,
   786  							},
   787  							Value:       4,
   788  							Description: "DI_GEAR_D",
   789  						},
   790  					},
   791  				},
   792  			},
   793  		},
   794  
   795  		{
   796  			name: "node_list.dbc",
   797  			text: `BU_: RSDS`,
   798  			defs: []Def{
   799  				&NodesDef{
   800  					Pos: scanner.Position{
   801  						Filename: "node_list.dbc",
   802  						Line:     1,
   803  						Column:   1,
   804  					},
   805  					NodeNames: []Identifier{"RSDS"},
   806  				},
   807  			},
   808  		},
   809  
   810  		{
   811  			name: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   812  			text: strings.Join([]string{
   813  				`BU_: RSDS`,
   814  				`VAL_TABLE_ TableName 3 "Value3" 2 "Value2" 1 "Value1" 0 "Value0";`,
   815  			}, "\n"),
   816  			defs: []Def{
   817  				&NodesDef{
   818  					Pos: scanner.Position{
   819  						Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   820  						Line:     1,
   821  						Column:   1,
   822  					},
   823  					NodeNames: []Identifier{"RSDS"},
   824  				},
   825  				&ValueTableDef{
   826  					Pos: scanner.Position{
   827  						Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   828  						Line:     2,
   829  						Column:   1,
   830  						Offset:   10,
   831  					},
   832  					TableName: "TableName",
   833  					ValueDescriptions: []ValueDescriptionDef{
   834  						{
   835  							Pos: scanner.Position{
   836  								Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   837  								Line:     2,
   838  								Column:   22,
   839  								Offset:   31,
   840  							},
   841  							Value:       3,
   842  							Description: "Value3",
   843  						},
   844  						{
   845  							Pos: scanner.Position{
   846  								Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   847  								Line:     2,
   848  								Column:   33,
   849  								Offset:   42,
   850  							},
   851  							Value:       2,
   852  							Description: "Value2",
   853  						},
   854  						{
   855  							Pos: scanner.Position{
   856  								Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   857  								Line:     2,
   858  								Column:   44,
   859  								Offset:   53,
   860  							},
   861  							Value:       1,
   862  							Description: "Value1",
   863  						},
   864  						{
   865  							Pos: scanner.Position{
   866  								Filename: "node_list_followed_by_single_newline_followed_by_value_table.dbc",
   867  								Line:     2,
   868  								Column:   55,
   869  								Offset:   64,
   870  							},
   871  							Value:       0,
   872  							Description: "Value0",
   873  						},
   874  					},
   875  				},
   876  			},
   877  		},
   878  
   879  		{
   880  			name: "signal_value_type.dbc",
   881  			text: `SIG_VALTYPE_ 42 TestSignal 2;`,
   882  			defs: []Def{
   883  				&SignalValueTypeDef{
   884  					Pos: scanner.Position{
   885  						Filename: "signal_value_type.dbc",
   886  						Line:     1,
   887  						Column:   1,
   888  					},
   889  					MessageID:       42,
   890  					SignalName:      "TestSignal",
   891  					SignalValueType: SignalValueTypeFloat64,
   892  				},
   893  			},
   894  		},
   895  
   896  		{
   897  			name: "signal_value_type_with_colon.dbc",
   898  			text: `SIG_VALTYPE_ 42 TestSignal : 2;`,
   899  			defs: []Def{
   900  				&SignalValueTypeDef{
   901  					Pos: scanner.Position{
   902  						Filename: "signal_value_type_with_colon.dbc",
   903  						Line:     1,
   904  						Column:   1,
   905  					},
   906  					MessageID:       42,
   907  					SignalName:      "TestSignal",
   908  					SignalValueType: SignalValueTypeFloat64,
   909  				},
   910  			},
   911  		},
   912  
   913  		{
   914  			name: "message_transmitters.dbc",
   915  			text: `BO_TX_BU_ 42: Node1 Node2;`,
   916  			defs: []Def{
   917  				&MessageTransmittersDef{
   918  					Pos: scanner.Position{
   919  						Filename: "message_transmitters.dbc",
   920  						Line:     1,
   921  						Column:   1,
   922  					},
   923  					MessageID:    42,
   924  					Transmitters: []Identifier{"Node1", "Node2"},
   925  				},
   926  			},
   927  		},
   928  
   929  		{
   930  			name: "message_transmitters_comma_separated.dbc",
   931  			text: `BO_TX_BU_ 42: Node1,Node2;`,
   932  			defs: []Def{
   933  				&MessageTransmittersDef{
   934  					Pos: scanner.Position{
   935  						Filename: "message_transmitters_comma_separated.dbc",
   936  						Line:     1,
   937  						Column:   1,
   938  					},
   939  					MessageID:    42,
   940  					Transmitters: []Identifier{"Node1", "Node2"},
   941  				},
   942  			},
   943  		},
   944  
   945  		{
   946  			name: "environment_variable_data.dbc",
   947  			text: `ENVVAR_DATA_ VariableName: 42;`,
   948  			defs: []Def{
   949  				&EnvironmentVariableDataDef{
   950  					Pos: scanner.Position{
   951  						Filename: "environment_variable_data.dbc",
   952  						Line:     1,
   953  						Column:   1,
   954  					},
   955  					EnvironmentVariableName: "VariableName",
   956  					DataSize:                42,
   957  				},
   958  			},
   959  		},
   960  
   961  		{
   962  			name: "environment_variable_value_descriptions.dbc",
   963  			text: `VAL_ VariableName 2 "Value2" 1 "Value1" 0 "Value0";`,
   964  			defs: []Def{
   965  				&ValueDescriptionsDef{
   966  					Pos: scanner.Position{
   967  						Filename: "environment_variable_value_descriptions.dbc",
   968  						Line:     1,
   969  						Column:   1,
   970  					},
   971  					ObjectType:              ObjectTypeEnvironmentVariable,
   972  					EnvironmentVariableName: "VariableName",
   973  					ValueDescriptions: []ValueDescriptionDef{
   974  						{
   975  							Pos: scanner.Position{
   976  								Filename: "environment_variable_value_descriptions.dbc",
   977  								Line:     1,
   978  								Column:   19,
   979  								Offset:   18,
   980  							},
   981  							Value:       2,
   982  							Description: "Value2",
   983  						},
   984  						{
   985  							Pos: scanner.Position{
   986  								Filename: "environment_variable_value_descriptions.dbc",
   987  								Line:     1,
   988  								Column:   30,
   989  								Offset:   29,
   990  							},
   991  							Value:       1,
   992  							Description: "Value1",
   993  						},
   994  						{
   995  							Pos: scanner.Position{
   996  								Filename: "environment_variable_value_descriptions.dbc",
   997  								Line:     1,
   998  								Column:   41,
   999  								Offset:   40,
  1000  							},
  1001  							Value:       0,
  1002  							Description: "Value0",
  1003  						},
  1004  					},
  1005  				},
  1006  			},
  1007  		},
  1008  
  1009  		{
  1010  			name: "unknown_def.dbc",
  1011  			text: `FOO_ Bar 2 Baz;`,
  1012  			defs: []Def{
  1013  				&UnknownDef{
  1014  					Pos: scanner.Position{
  1015  						Filename: "unknown_def.dbc",
  1016  						Line:     1,
  1017  						Column:   1,
  1018  					},
  1019  					Keyword: "FOO_",
  1020  				},
  1021  			},
  1022  		},
  1023  	} {
  1024  		tt := tt
  1025  		t.Run(tt.name, func(t *testing.T) {
  1026  			p := NewParser(tt.name, []byte(tt.text))
  1027  			assert.NilError(t, p.Parse())
  1028  			assert.DeepEqual(t, tt.defs, p.Defs())
  1029  		})
  1030  	}
  1031  }
  1032  
  1033  func TestParser_Parse_Error(t *testing.T) {
  1034  	for _, tt := range []struct {
  1035  		name string
  1036  		text string
  1037  		err  *parseError
  1038  	}{
  1039  		{
  1040  			name: "non_string_version.dbc",
  1041  			text: "VERSION foo",
  1042  			err: &parseError{
  1043  				pos: scanner.Position{
  1044  					Filename: "non_string_version.dbc",
  1045  					Line:     1,
  1046  					Column:   9,
  1047  					Offset:   8,
  1048  				},
  1049  				reason: "expected token \"",
  1050  			},
  1051  		},
  1052  		{
  1053  			name: "invalid_utf8.dbc",
  1054  			text: `VERSION "foo` + string([]byte{0xc3, 0x28}) + `"`,
  1055  			err: &parseError{
  1056  				pos: scanner.Position{
  1057  					Filename: "invalid_utf8.dbc",
  1058  					Line:     1,
  1059  					Column:   13,
  1060  					Offset:   12,
  1061  				},
  1062  				reason: "invalid UTF-8 encoding",
  1063  			},
  1064  		},
  1065  	} {
  1066  		tt := tt
  1067  		t.Run(tt.name, func(t *testing.T) {
  1068  			p := NewParser(tt.name, []byte(tt.text))
  1069  			assert.Error(t, p.Parse(), tt.err.Error())
  1070  		})
  1071  	}
  1072  }
  1073  
  1074  func dump(data interface{}) string {
  1075  	spewConfig := spew.ConfigState{
  1076  		Indent:                  " ",
  1077  		DisablePointerAddresses: true,
  1078  		DisableCapacities:       true,
  1079  		SortKeys:                true,
  1080  	}
  1081  	return spewConfig.Sdump(data)
  1082  }