Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/blueprint/parser/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 19 kB image not shown  

Quelle  parser_test.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package parser

import (
 "bytes"
 "errors"
 "reflect"
 "strconv"
 "strings"
 "testing"
 "text/scanner"
)

func mkpos(offset, line, column int) scanner.Position {
 return scanner.Position{
  Offset: offset,
  Line:   line,
  Column: column,
 }
}

var validParseTestCases = []struct {
 input    string
 defs     []Definition
 comments []*CommentGroup
}{
 {`
  foo {}
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(828),
    },
   },
  },
  nil,
 },

 {`
  foo {
   name: "abc",
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(2743),
     Properties: []*Property{
      {
       Name:     "name",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(1638),
       Value: &String{
        LiteralPos: mkpos(18310),
        Value:      "abc",
       },
      },
     },
    },
   },
  },
  nil,
 },

 {`
  foo {
   isGood: true,
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(2843),
     Properties: []*Property{
      {
       Name:     "isGood",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(18310),
       Value: &Bool{
        LiteralPos: mkpos(20312),
        Value:      true,
        Token:      "true",
       },
      },
     },
    },
   },
  },
  nil,
 },

 {`
  foo {
   num: 4,
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(2243),
     Properties: []*Property{
      {
       Name:     "num",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(1537),
       Value: &Int64{
        LiteralPos: mkpos(1739),
        Value:      4,
        Token:      "4",
       },
      },
     },
    },
   },
  },
  nil,
 },

 {`
  foo {
   stuff: ["asdf", "jkl;", "qwert",
    "uiop", ` + "`bnm,\n`" +
  `]
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(6863),
     Properties: []*Property{
      {
       Name:     "stuff",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(1739),
       Value: &List{
        LBracePos: mkpos(19311),
        RBracePos: mkpos(6452),
        Values: []Expression{
         &String{
          LiteralPos: mkpos(20312),
          Value:      "asdf",
         },
         &String{
          LiteralPos: mkpos(28320),
          Value:      "jkl;",
         },
         &String{
          LiteralPos: mkpos(36328),
          Value:      "qwert",
         },
         &String{
          LiteralPos: mkpos(4945),
          Value:      "uiop",
         },
         &String{
          LiteralPos: mkpos(57413),
          Value:      "bnm,\n",
         },
        },
       },
      },
     },
    },
   },
  },
  nil,
 },

 {
  `
  foo {
   list_of_maps: [
    {
     var: true,
     name: "a",
    },
    {
     var: false,
     name: "b",
    },
   ],
  }
`,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(127133),
     Properties: []*Property{
      {
       Name:     "list_of_maps",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(24316),
       Value: &List{
        LBracePos: mkpos(26318),
        RBracePos: mkpos(122124),
        Values: []Expression{
         &Map{
          LBracePos: mkpos(3245),
          RBracePos: mkpos(7075),
          Properties: []*Property{
           {
            Name:     "var",
            NamePos:  mkpos(3956),
            ColonPos: mkpos(4259),
            Value: &Bool{
             LiteralPos: mkpos(44511),
             Value:      true,
             Token:      "true",
            },
           },
           {
            Name:     "name",
            NamePos:  mkpos(5566),
            ColonPos: mkpos(59610),
            Value: &String{
             LiteralPos: mkpos(61612),
             Value:      "a",
            },
           },
          },
         },
         &Map{
          LBracePos: mkpos(7785),
          RBracePos: mkpos(116115),
          Properties: []*Property{
           {
            Name:     "var",
            NamePos:  mkpos(8496),
            ColonPos: mkpos(8799),
            Value: &Bool{
             LiteralPos: mkpos(89911),
             Value:      false,
             Token:      "false",
            },
           },
           {
            Name:     "name",
            NamePos:  mkpos(101106),
            ColonPos: mkpos(1051010),
            Value: &String{
             LiteralPos: mkpos(1071012),
             Value:      "b",
            },
           },
          },
         },
        },
       },
      },
     },
    },
   },
  },
  nil,
 },
 {
  `
  foo {
   list_of_lists: [
    [ "a", "b" ],
    [ "c", "d" ]
   ],
  }
`,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(7273),
     Properties: []*Property{
      {
       Name:     "list_of_lists",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(25317),
       Value: &List{
        LBracePos: mkpos(27319),
        RBracePos: mkpos(6764),
        Values: []Expression{
         &List{
          LBracePos: mkpos(3345),
          RBracePos: mkpos(44416),
          Values: []Expression{
           &String{
            LiteralPos: mkpos(3547),
            Value:      "a",
           },
           &String{
            LiteralPos: mkpos(40412),
            Value:      "b",
           },
          },
         },
         &List{
          LBracePos: mkpos(5155),
          RBracePos: mkpos(62516),
          Values: []Expression{
           &String{
            LiteralPos: mkpos(5357),
            Value:      "c",
           },
           &String{
            LiteralPos: mkpos(58512),
            Value:      "d",
           },
          },
         },
        },
       },
      },
     },
    },
   },
  },
  nil,
 },
 {`
  foo {
   stuff: {
    isGood: true,
    name: "bar",
    num: 36,
   }
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(7683),
     Properties: []*Property{
      {
       Name:     "stuff",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(1739),
       Value: &Map{
        LBracePos: mkpos(19311),
        RBracePos: mkpos(7274),
        Properties: []*Property{
         {
          Name:     "isGood",
          NamePos:  mkpos(2545),
          ColonPos: mkpos(31411),
          Value: &Bool{
           LiteralPos: mkpos(33413),
           Value:      true,
           Token:      "true",
          },
         },
         {
          Name:     "name",
          NamePos:  mkpos(4355),
          ColonPos: mkpos(4759),
          Value: &String{
           LiteralPos: mkpos(49511),
           Value:      "bar",
          },
         },
         {
          Name:     "num",
          NamePos:  mkpos(6065),
          ColonPos: mkpos(6368),
          Value: &Int64{
           LiteralPos: mkpos(65610),
           Value:      36,
           Token:      "36",
          },
         },
        },
       },
      },
     },
    },
   },
  },
  nil,
 },

 {`
  // comment1
  foo /* test */ {
   // comment2
   isGood: true,  // comment3
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(1733),
    Map: Map{
     LBracePos: mkpos(32318),
     RBracePos: mkpos(8163),
     Properties: []*Property{
      {
       Name:     "isGood",
       NamePos:  mkpos(5254),
       ColonPos: mkpos(58510),
       Value: &Bool{
        LiteralPos: mkpos(60512),
        Value:      true,
        Token:      "true",
       },
      },
     },
    },
   },
  },
  []*CommentGroup{
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"// comment1"},
      Slash:   mkpos(323),
     },
    },
   },
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"/* test */"},
      Slash:   mkpos(2137),
     },
    },
   },
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"// comment2"},
      Slash:   mkpos(3744),
     },
    },
   },
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"// comment3"},
      Slash:   mkpos(67519),
     },
    },
   },
  },
 },

 {`
  foo {
   name: "abc",
   num: 4,
  }

  bar {
   name: "def",
   num: -5,
  }
  `,
  []Definition{
   &Module{
    Type:    "foo",
    TypePos: mkpos(323),
    Map: Map{
     LBracePos: mkpos(727),
     RBracePos: mkpos(3853),
     Properties: []*Property{
      {
       Name:     "name",
       NamePos:  mkpos(1234),
       ColonPos: mkpos(1638),
       Value: &String{
        LiteralPos: mkpos(18310),
        Value:      "abc",
       },
      },
      {
       Name:     "num",
       NamePos:  mkpos(2844),
       ColonPos: mkpos(3147),
       Value: &Int64{
        LiteralPos: mkpos(3349),
        Value:      4,
        Token:      "4",
       },
      },
     },
    },
   },
   &Module{
    Type:    "bar",
    TypePos: mkpos(4373),
    Map: Map{
     LBracePos: mkpos(4777),
     RBracePos: mkpos(79103),
     Properties: []*Property{
      {
       Name:     "name",
       NamePos:  mkpos(5284),
       ColonPos: mkpos(5688),
       Value: &String{
        LiteralPos: mkpos(58810),
        Value:      "def",
       },
      },
      {
       Name:     "num",
       NamePos:  mkpos(6894),
       ColonPos: mkpos(7197),
       Value: &Int64{
        LiteralPos: mkpos(7399),
        Value:      -5,
        Token:      "-5",
       },
      },
     },
    },
   },
  },
  nil,
 },

 {`
  foo = "stuff"
  bar = foo
  baz = foo + bar
  boo = baz
  boo += foo
  `,
  []Definition{
   &Assignment{
    Name:      "foo",
    NamePos:   mkpos(323),
    EqualsPos: mkpos(727),
    Value: &String{
     LiteralPos: mkpos(929),
     Value:      "stuff",
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "bar",
    NamePos:   mkpos(1933),
    EqualsPos: mkpos(2337),
    Value: &Variable{
     Name:    "foo",
     NamePos: mkpos(2539),
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "baz",
    NamePos:   mkpos(3143),
    EqualsPos: mkpos(3547),
    Value: &Operator{
     OperatorPos: mkpos(41413),
     Operator:    '+',
     Args: [2]Expression{
      &Variable{
       Name:    "foo",
       NamePos: mkpos(3749),
      },
      &Variable{
       Name:    "bar",
       NamePos: mkpos(43415),
      },
     },
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "boo",
    NamePos:   mkpos(4953),
    EqualsPos: mkpos(5357),
    Value: &Variable{
     Name:    "baz",
     NamePos: mkpos(5559),
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "boo",
    NamePos:   mkpos(6163),
    EqualsPos: mkpos(6668),
    Value: &Variable{
     Name:    "foo",
     NamePos: mkpos(68610),
    },
    Assigner: "+=",
   },
  },
  nil,
 },

 {`
  baz = -4 + -5 + 6
  `,
  []Definition{
   &Assignment{
    Name:      "baz",
    NamePos:   mkpos(323),
    EqualsPos: mkpos(727),
    Value: &Operator{
     OperatorPos: mkpos(12212),
     Operator:    '+',
     Args: [2]Expression{
      &Int64{
       LiteralPos: mkpos(929),
       Value:      -4,
       Token:      "-4",
      },
      &Operator{
       OperatorPos: mkpos(17217),
       Operator:    '+',
       Args: [2]Expression{
        &Int64{
         LiteralPos: mkpos(14214),
         Value:      -5,
         Token:      "-5",
        },
        &Int64{
         LiteralPos: mkpos(19219),
         Value:      6,
         Token:      "6",
        },
       },
      },
     },
    },
    Assigner: "=",
   },
  },
  nil,
 },

 {`
  foo = 1000000
  bar = foo
  baz = foo + bar
  boo = baz
  boo += foo
  `,
  []Definition{
   &Assignment{
    Name:      "foo",
    NamePos:   mkpos(323),
    EqualsPos: mkpos(727),
    Value: &Int64{
     LiteralPos: mkpos(929),
     Value:      1000000,
     Token:      "1000000",
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "bar",
    NamePos:   mkpos(1933),
    EqualsPos: mkpos(2337),
    Value: &Variable{
     Name:    "foo",
     NamePos: mkpos(2539),
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "baz",
    NamePos:   mkpos(3143),
    EqualsPos: mkpos(3547),
    Value: &Operator{
     OperatorPos: mkpos(41413),
     Operator:    '+',
     Args: [2]Expression{
      &Variable{
       Name:    "foo",
       NamePos: mkpos(3749),
      },
      &Variable{
       Name:    "bar",
       NamePos: mkpos(43415),
      },
     },
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "boo",
    NamePos:   mkpos(4953),
    EqualsPos: mkpos(5357),
    Value: &Variable{
     Name:    "baz",
     NamePos: mkpos(5559),
    },
    Assigner: "=",
   },
   &Assignment{
    Name:      "boo",
    NamePos:   mkpos(6163),
    EqualsPos: mkpos(6668),
    Value: &Variable{
     Name:    "foo",
     NamePos: mkpos(68610),
    },
    Assigner: "+=",
   },
  },
  nil,
 },

 {`
  // comment1
  // comment2

  /* comment3
     comment4 */
  // comment5

  /* comment6 */ /* comment7 */ // comment8
  `,
  nil,
  []*CommentGroup{
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"// comment1"},
      Slash:   mkpos(323),
     },
     &Comment{
      Comment: []string{"// comment2"},
      Slash:   mkpos(1733),
     },
    },
   },
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"/* comment3", "     comment4 */"},
      Slash:   mkpos(3253),
     },
     &Comment{
      Comment: []string{"// comment5"},
      Slash:   mkpos(6373),
     },
    },
   },
   {
    Comments: []*Comment{
     &Comment{
      Comment: []string{"/* comment6 */"},
      Slash:   mkpos(7893),
     },
     &Comment{
      Comment: []string{"/* comment7 */"},
      Slash:   mkpos(93918),
     },
     &Comment{
      Comment: []string{"// comment8"},
      Slash:   mkpos(108933),
     },
    },
   },
  },
 },
}

func TestParseValidInput(t *testing.T) {
 for i, testCase := range validParseTestCases {
  t.Run(strconv.Itoa(i), func(t *testing.T) {
   r := bytes.NewBufferString(testCase.input)
   file, errs := Parse("", r)
   if len(errs) != 0 {
    t.Errorf("test case: %s", testCase.input)
    t.Errorf("unexpected errors:")
    for _, err := range errs {
     t.Errorf("  %s", err)
    }
    t.FailNow()
   }

   if len(file.Defs) == len(testCase.defs) {
    for i := range file.Defs {
     if !reflect.DeepEqual(file.Defs[i], testCase.defs[i]) {
      t.Errorf("test case: %s", testCase.input)
      t.Errorf("incorrect definition %d:", i)
      t.Errorf("  expected: %s", testCase.defs[i])
      t.Errorf("       got: %s", file.Defs[i])
     }
    }
   } else {
    t.Errorf("test case: %s", testCase.input)
    t.Errorf("length mismatch, expected %d definitions, got %d",
     len(testCase.defs), len(file.Defs))
   }

   if len(file.Comments) == len(testCase.comments) {
    for i := range file.Comments {
     if !reflect.DeepEqual(file.Comments[i], testCase.comments[i]) {
      t.Errorf("test case: %s", testCase.input)
      t.Errorf("incorrect comment %d:", i)
      t.Errorf("  expected: %s", testCase.comments[i])
      t.Errorf("       got: %s", file.Comments[i])
     }
    }
   } else {
    t.Errorf("test case: %s", testCase.input)
    t.Errorf("length mismatch, expected %d comments, got %d",
     len(testCase.comments), len(file.Comments))
   }
  })
 }
}

func TestParseSelectWithoutTrailingComma(t *testing.T) {
 r := bytes.NewBufferString(`
 m {
  foo: select(arch(), {
   "arm64": true,
   default: false
  }),
 }
 `)
 file, errs := ParseAndEval("", r, NewScope(nil))
 if len(errs) != 0 {
  t.Fatalf("%s", errors.Join(errs...).Error())
 }
 _, ok := file.Defs[0].(*Module).Properties[0].Value.(*Select)
 if !ok {
  t.Fatalf("did not parse to select")
 }
}

func TestParserError(t *testing.T) {
 testcases := []struct {
  name  string
  input string
  err   string
 }{
  {
   name:  "invalid first token",
   input: "\x00",
   err:   "invalid character NUL",
  },
  {
   name: "select with duplicate condition",
   input: `
   m {
    foo: select((arch(), arch()), {
     (default, default): true,
    }),
   }
   `,
   err: "Duplicate select condition found: arch()",
  },
  {
   name: "select with duplicate binding",
   input: `
   m {
    foo: select((arch(), os()), {
     (any @ bar, any @ bar): true,
    }),
   }
   `,
   err: "Found duplicate select pattern binding: bar",
  },
  // TODO: test more parser errors
 }

 for _, tt := range testcases {
  t.Run(tt.name, func(t *testing.T) {
   r := bytes.NewBufferString(tt.input)
   _, errs := ParseAndEval("", r, NewScope(nil))
   if len(errs) == 0 {
    t.Fatalf("missing expected error")
   }
   if g, w := errs[0], tt.err; !strings.Contains(g.Error(), w) {
    t.Errorf("expected error %q, got %q", w, g)
   }
   for _, err := range errs[1:] {
    t.Errorf("got unexpected extra error %q", err)
   }
  })
 }
}

func TestParserEndPos(t *testing.T) {
 in := `
  module {
   string: "string",
   stringexp: "string1" + "string2",
   int: -1,
   intexp: -1 + 2,
   list: ["a", "b"],
   listexp: ["c"] + ["d"],
   multilinelist: [
    "e",
    "f",
   ],
   map: {
    prop: "abc",
   },
  }
 `

 // Strip each line to make it easier to compute the previous "," from each property
 lines := strings.Split(in, "\n")
 for i := range lines {
  lines[i] = strings.TrimSpace(lines[i])
 }
 in = strings.Join(lines, "\n")

 r := bytes.NewBufferString(in)

 file, errs := Parse("", r)
 if len(errs) != 0 {
  t.Errorf("unexpected errors:")
  for _, err := range errs {
   t.Errorf("  %s", err)
  }
  t.FailNow()
 }

 mod := file.Defs[0].(*Module)
 modEnd := mkpos(len(in)-1, len(lines)-12)
 if mod.End() != modEnd {
  t.Errorf("expected mod.End() %s, got %s", modEnd, mod.End())
 }

 nextPos := make([]scanner.Position, len(mod.Properties))
 for i := 0; i < len(mod.Properties)-1; i++ {
  nextPos[i] = mod.Properties[i+1].Pos()
 }
 nextPos[len(mod.Properties)-1] = mod.RBracePos

 for i, cur := range mod.Properties {
  endOffset := nextPos[i].Offset - len(",\n")
  endLine := nextPos[i].Line - 1
  endColumn := len(lines[endLine-1]) // scanner.Position.Line is starts at 1
  endPos := mkpos(endOffset, endLine, endColumn)
  if cur.End() != endPos {
   t.Errorf("expected property %s End() %s@%d, got %s@%d", cur.Name, endPos, endPos.Offset, cur.End(), cur.End().Offset)
  }
 }
}

func TestParserNotEvaluated(t *testing.T) {
 // When parsing without evaluation, create variables correctly
 input := "FOO=abc\n"
 file, errs := Parse("", bytes.NewBufferString(input))
 if errs != nil {
  t.Errorf("unexpected errors:")
  for _, err := range errs {
   t.Errorf("  %s", err)
  }
  t.FailNow()
 }
 assignment, ok := file.Defs[0].(*Assignment)
 if !ok || assignment.Name != "FOO" {
  t.Fatalf("Expected to find FOO after parsing %s", input)
 }
 if assignment.Value.String() != "abc" {
  t.Errorf("Attempt to print FOO returned %s", assignment.Value.String())
 }
}

[Dauer der Verarbeitung: 0.25 Sekunden, vorverarbeitet 2026-06-28]