package main import ( "encoding/json" "flag" "fmt" "os" "github.com/iancoleman/orderedmap" ) type TestDefinitions struct { Name string `json:"name"` TestCases []TestCase `json:"testCases"` BaseUrl string `json:"url"` Headers map[string]string // Need to initialise with make //Header HeaderOptions `json:"header"` } type TestCase struct { Name string Path string `json:"path"` Method string `json:"method"` Description string `json:"description"` Expect ExpectOptions `json:"expect"` } type ExpectOptions struct { Header HeaderOptions `json:"header"` Body BodyOptions `json:"body"` } type HeaderOptions struct { Contains ContainsTest `json:"contains"` Equals EqualsTest `json:"equals"` } type BodyOptions struct { Contains ContainsTest `json:"contains"` Equals EqualsTest `json:"equals"` HasKeys HasKeysTest `json:"hasKeys"` PathEq PathEqTest `json:"pathEq"` PathContains PathContainsTest `json:"pathContains"` } // Test types type ContainsTest struct { // dynamically specified key value pairs } type EqualsTest struct { // dynamically specified key value pairs } type HasKeysTest struct { // dynamically specified key value pairs } type PathEqTest struct { // dynamically specified key value pairs } type PathContainsTest struct { // dynamically specified key value pairs } // fileExists returns true if the specified file exists and is not a directory func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { return false } return !info.IsDir() } func PerformGet() { } func PerformPost() { } func TestOutput() { } func main() { var s []byte var err error var ok bool // Prepare struct to store settings common to all tests testDefinitions := new(TestDefinitions) testDefinitions.Headers = make(map[string]string) //testCaseDefinition := new(InputData) // Command line arguments var inputJson string // Process command line arguments flag.StringVar(&inputJson, "input", "./tests.json", "Full path to input json test definition file") // Read the json input file if fileExists(inputJson) { s, err = os.ReadFile(inputJson) if err != nil { panic(err) } } else { fmt.Printf("Input JSON file '%s' does not exist.\n", inputJson) os.Exit(1) } // Unmarshal the json into an orderedmap to preserve the ordering of json structure o := orderedmap.New() err = json.Unmarshal([]byte(s), &o) if err != nil { error := fmt.Sprintf("JSON Unmarshal error %s\n", err) panic(error) } topLevel := o.Keys() fmt.Printf("Found %d top-level keys in json data\n", len(topLevel)) /* for i, key := range topLevel { fmt.Printf("[%d] : %s\n", i, key) } */ // TODO : Check required top level keys are present if len(topLevel) <= 1 { error := "Missing required keys in input json" panic(error) } // Get the name of the group of tests if data, ok := o.Get("name"); ok { testDefinitions.Name = data.(string) fmt.Printf("test name: '%s'\n", testDefinitions.Name) } // Get a reference to the node containing each of the test cases testsInterface, ok := o.Get("testCases") if !ok { fmt.Printf("No key defining test cases found\n") } /* // Test Cases is an array, need to go one level down before we start looking at key/values vs := testsInterface.([]interface{}) fmt.Printf("Listing %d test definitions\n", len(vs)) for i, vInterface := range vs { v := vInterface.(orderedmap.OrderedMap) keys := v.Keys() fmt.Printf("Test %d\n", i) for j := range keys { fmt.Printf("[%d] : %s\n", j, keys[j]) } } */ /* vslice := testsInterface.([]interface{}) vmap := vslice[2].(orderedmap.OrderedMap) k := vmap.Keys() for i := range k { fmt.Printf("[%d] : %s\n", i, k[i]) } return */ // Get the keys for the first test so we know what config options have been specified testCasesMap := testsInterface.(orderedmap.OrderedMap) testCasesKeys := testCasesMap.Keys() // Parse json into our testCaseDefinition // Parse each key into our config struct fmt.Printf("Listing %d test cases\n", len(testCasesKeys)) for i, outerKey := range testCasesKeys { fmt.Printf("Test %d : %s\n", i, outerKey) thisTestCase := new(TestCase) thisTestCase.Name = outerKey if testCase, ok := testCasesMap.Get(outerKey); ok { // Get the details of the test case thisTestCaseMap := testCase.(orderedmap.OrderedMap) // Path if val, ok := thisTestCaseMap.Get("path"); ok { thisTestCase.Path = val.(string) } // Method if val, ok := thisTestCaseMap.Get("method"); ok { thisTestCase.Method = val.(string) } // Description if val, ok := thisTestCaseMap.Get("description"); ok { thisTestCase.Description = val.(string) } // Expect - this is more tricky since it is yet another json fragment /* for j, key := range thisTestCaseMap.Keys() { val, _ := thisTestCaseMap.Get(key) fmt.Printf("[%d] %s : %s\n", j, key, val) } */ } testDefinitions.TestCases = append(testDefinitions.TestCases, *thisTestCase) } // For debugging, just dump the output fmt.Printf("%+v\n", testDefinitions) }