/* * ECAL * * Copyright 2020 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the MIT * License, If a copy of the MIT License was not distributed with this * file, You can obtain one at https://opensource.org/licenses/MIT. */ package parser import ( "encoding/json" "flag" "fmt" "os" "testing" ) // Main function for all tests in this package func TestMain(m *testing.M) { flag.Parse() res := m.Run() // Check if all nodes have been tested for _, n := range astNodeMap { if _, ok := usedNodes[n.Name]; !ok { fmt.Println("Not tested node: ", n.Name) } } // Check if all nodes have been pretty printed for k := range prettyPrinterMap { if _, ok := usedPrettyPrinterNodes[k]; !ok { fmt.Println("Not tested pretty printer: ", k) } } os.Exit(res) } // Used nodes map which is filled during unit testing. Prefilled with tokens which // will not be generated by the parser // var usedNodes = map[string]bool{ NodeEOF: true, // Only used as end term "": true, // No node e.g. semicolon - These nodes should never be part of an AST } func UnitTestParse(name string, input string) (*ASTNode, error) { return UnitTestParseWithPPResult(name, input, "") } func UnitTestParseWithPPResult(name string, input string, expectedPPRes string) (*ASTNode, error) { n, err := ParseWithRuntime(name, input, &DummyRuntimeProvider{}) // Test AST serialization if err == nil { var unmarshaledJSONObject map[string]interface{} astString, err := json.Marshal(n.ToJSONObject()) if err != nil { return nil, fmt.Errorf("Could not marshal AST: %v", err) } if err := json.Unmarshal(astString, &unmarshaledJSONObject); err != nil { return nil, fmt.Errorf("Could not unmarshal JSON object: %v", err) } unmarshaledAST, err := ASTFromJSONObject(unmarshaledJSONObject) if err != nil { return nil, fmt.Errorf("Could not create AST from unmarshaled JSON object: %v", err) } // Compare the ASTs if ok, msg := n.Equals(unmarshaledAST, false); !ok { return nil, fmt.Errorf( "Parsed AST is different from the unmarshaled AST."+ "\n%v\n", msg) } } // Test Pretty printing if err == nil { ppres, err := PrettyPrint(n) if err != nil { return nil, fmt.Errorf("Error while pretty printing: %v (input: %v)", err, input) } if expectedPPRes == "" { n2, err := ParseWithRuntime(name, ppres, &DummyRuntimeProvider{}) if err != nil { return nil, fmt.Errorf("Error while parsing pretty print result: %v (result: %v)", err, ppres) } // Compare the ASTs if ok, msg := n.Equals(n2, true); !ok { return nil, fmt.Errorf( "Parsed AST from pretty printer is different from the originally parsed AST."+ "\nOriginal input: %v\nPretty printed: %v\nPretty AST: %v\n%v\n", input, ppres, n2, msg) } } else if ppres != expectedPPRes { return nil, fmt.Errorf("Expected pretty printer result is different:\nExpected "+ "result: %v\nActual result: %v\n", expectedPPRes, ppres) } markASTNodesAsPrettyPrinted(n) } return n, err } // Used nodes map which is filled during unit testing. Prefilled with tokens which // will not be generated by the parser // var usedPrettyPrinterNodes = map[string]bool{} func markASTNodesAsPrettyPrinted(n *ASTNode) { // Make the encountered node as used numChildren := len(n.Children) if numChildren > 0 { usedPrettyPrinterNodes[fmt.Sprintf("%v_%v", n.Name, numChildren)] = true } else { usedPrettyPrinterNodes[n.Name] = true } for _, c := range n.Children { markASTNodesAsPrettyPrinted(c) } } func UnitTestPrettyPrinting(input, astOutput, ppOutput string) error { astres, err := ParseWithRuntime("mytest", input, &DummyRuntimeProvider{}) if err != nil || (astOutput != "" && fmt.Sprint(astres) != astOutput) { return fmt.Errorf("Unexpected parser output:\n%v expected was:\n%v Error: %v", astres, astOutput, err) } markASTNodesAsPrettyPrinted(astres) ppres, err := PrettyPrint(astres) if err != nil || ppres != ppOutput { return fmt.Errorf("Unexpected result: %v (expected: %v) error: %v", ppres, ppOutput, err) } // Make sure the pretty printed result is valid and gets the same parse tree astres2, err := ParseWithRuntime("mytest", ppres, &DummyRuntimeProvider{}) if err != nil || (astOutput != "" && fmt.Sprint(astres2) != astOutput) { return fmt.Errorf("Unexpected parser output from pretty print string:\n%v expected was:\n%v Error: %v", astres2, astOutput, err) } return nil } // Helper objects type DummyRuntimeProvider struct { } func (d *DummyRuntimeProvider) Runtime(n *ASTNode) Runtime { // Make the encountered node as used usedNodes[n.Name] = true return nil }