github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/test_compare.go (about)

     1  package lang
     2  
     3  /*
     4  	This test library relates to the testing framework within the murex
     5  	language itself rather than Go's test framework within the murex project.
     6  
     7  	The naming convention here is basically the inverse of Go's test naming
     8  	convention. ie Go source files will be named "test_unit.go" (because
     9  	calling it unit_test.go would mean it's a Go test rather than murex test)
    10  	and the code is named UnitTestPlans (etc) rather than TestUnitPlans (etc)
    11  	because the latter might suggest they would be used by `go test`. This
    12  	naming convention is a little counterintuitive but it at least avoids
    13  	naming conflicts with `go test`.
    14  */
    15  
    16  import (
    17  	"github.com/lmorg/murex/utils"
    18  )
    19  
    20  // Compare is the method which actually runs the individual test cases
    21  // to see if they pass or fail.
    22  func (tests *Tests) Compare(name string, p *Process) {
    23  	tests.mutex.Lock()
    24  
    25  	var i int
    26  	for ; i < len(tests.test); i++ {
    27  		if tests.test[i].Name == name {
    28  			goto compare
    29  		}
    30  	}
    31  
    32  	tests.mutex.Unlock()
    33  
    34  	tests.AddResult(&TestProperties{Name: name}, p, TestError, "Test named but there is no test defined")
    35  	return
    36  
    37  compare:
    38  
    39  	var failed bool
    40  	test := tests.test[i]
    41  	test.HasRan = true
    42  	tests.mutex.Unlock()
    43  
    44  	// read stdout
    45  	stdout, err := test.out.stdio.ReadAll()
    46  	if err != nil {
    47  		failed = true
    48  		tests.AddResult(test, p, TestError, tMsgReadErr("stdout", name, err))
    49  	}
    50  	stdout = utils.CrLfTrim(stdout)
    51  
    52  	// read stderr
    53  	stderr, err := test.err.stdio.ReadAll()
    54  	if err != nil {
    55  		failed = true
    56  		tests.AddResult(test, p, TestError, tMsgReadErr("stderr", name, err))
    57  	}
    58  	stderr = utils.CrLfTrim(stderr)
    59  
    60  	// compare stdout
    61  	if len(test.out.Block) != 0 {
    62  		testBlock(test, p, test.out.Block, stdout, test.out.stdio.GetDataType(), "StdoutBlock", &failed)
    63  	}
    64  
    65  	if test.out.Regexp != nil {
    66  		if test.out.Regexp.Match(stdout) {
    67  			tests.AddResult(test, p, TestInfo, tMsgRegexMatch("StdoutRegex"))
    68  		} else {
    69  			failed = true
    70  			tests.AddResult(test, p, TestFailed, tMsgRegexMismatch("StdoutRegex", stdout))
    71  		}
    72  	}
    73  
    74  	// compare stderr
    75  	if len(test.err.Block) != 0 {
    76  		testBlock(test, p, test.err.Block, stderr, test.err.stdio.GetDataType(), "StderrBlock", &failed)
    77  	}
    78  
    79  	if test.err.Regexp != nil {
    80  		if test.err.Regexp.Match(stderr) {
    81  			tests.AddResult(test, p, TestInfo, tMsgRegexMatch("StderrRegex"))
    82  		} else {
    83  			failed = true
    84  			tests.AddResult(test, p, TestFailed, tMsgRegexMismatch("StderrRegex", stderr))
    85  		}
    86  	}
    87  
    88  	// test exit number
    89  	if test.exitNum != *test.exitNumPtr {
    90  		failed = true
    91  		tests.AddResult(test, p, TestFailed, tMsgExitNumMismatch(test.exitNum, *test.exitNumPtr))
    92  
    93  	} else {
    94  		tests.AddResult(test, p, TestInfo, tMsgExitNumMatch())
    95  	}
    96  
    97  	// if not failed, log a success result
    98  	if !failed {
    99  		tests.AddResult(test, p, TestPassed, tMsgPassed())
   100  	}
   101  }
   102  
   103  // ReportMissedTests is used so we have a result of tests that didn't run
   104  func (tests *Tests) ReportMissedTests(p *Process) {
   105  	tests.mutex.Lock()
   106  
   107  	for _, test := range tests.test {
   108  		if test.HasRan {
   109  			continue
   110  		}
   111  
   112  		tests.AddResult(test, &Process{Config: p.Config}, TestMissed, "Test was defined but no function ran against that test pipe.")
   113  	}
   114  
   115  	tests.mutex.Unlock()
   116  }
   117  
   118  func testIsMap(b []byte, dt string, property string) (TestStatus, string) {
   119  	fork := ShellProcess.Fork(F_CREATE_STDIN)
   120  	fork.Stdin.SetDataType(dt)
   121  	_, err := fork.Stdin.Write(b)
   122  	if err != nil {
   123  		return TestError, tMsgWriteErr(property, err)
   124  	}
   125  
   126  	v, err := UnmarshalData(fork.Process, dt)
   127  	if err != nil {
   128  		return TestFailed, tMsgUnmarshalErr(property, dt, err)
   129  	}
   130  
   131  	switch v.(type) {
   132  	case map[string]string, map[string]interface{}, map[interface{}]string, map[interface{}]interface{}:
   133  		return TestPassed, tMsgDataFormatValid(property, dt, v)
   134  
   135  	default:
   136  		return TestFailed, tMsgDataFormatInvalid(property, dt, v)
   137  	}
   138  }
   139  
   140  func testIsArray(b []byte, dt string, property string) (TestStatus, string) {
   141  	fork := ShellProcess.Fork(F_CREATE_STDIN)
   142  	fork.Stdin.SetDataType(dt)
   143  	_, err := fork.Stdin.Write(b)
   144  	if err != nil {
   145  		return TestError, tMsgWriteErr(property, err)
   146  	}
   147  
   148  	v, err := UnmarshalData(fork.Process, dt)
   149  	if err != nil {
   150  		return TestFailed, tMsgUnmarshalErr(property, dt, err)
   151  	}
   152  
   153  	switch v.(type) {
   154  	case []string, []interface{}:
   155  		return TestPassed, tMsgDataFormatValid(property, dt, v)
   156  
   157  	default:
   158  		return TestFailed, tMsgDataFormatInvalid(property, dt, v)
   159  	}
   160  }
   161  
   162  func testIsGreaterThanOrEqualTo(b []byte, dt string, property string, comparison int) (TestStatus, string) {
   163  	fork := ShellProcess.Fork(F_CREATE_STDIN)
   164  	fork.Stdin.SetDataType(dt)
   165  	_, err := fork.Stdin.Write(b)
   166  	if err != nil {
   167  		return TestError, tMsgWriteErr(property, err)
   168  	}
   169  
   170  	v, err := UnmarshalData(fork.Process, dt)
   171  	if err != nil {
   172  		return TestFailed, tMsgUnmarshalErr(property, dt, err)
   173  	}
   174  
   175  	var l int
   176  	switch t := v.(type) {
   177  	case []string:
   178  		l = len(t)
   179  	case []float64:
   180  		l = len(t)
   181  	case []int:
   182  		l = len(t)
   183  	case []bool:
   184  		l = len(t)
   185  	case []any:
   186  		l = len(t)
   187  
   188  	case [][]string:
   189  		l = len(t)
   190  	case [][]any:
   191  		l = len(t)
   192  
   193  	case map[string]string:
   194  		l = len(t)
   195  	case map[string]any:
   196  		l = len(t)
   197  	case map[any]any:
   198  		l = len(t)
   199  
   200  	default:
   201  		return TestFailed, tMsgDataFormatInvalid(property, dt, v)
   202  	}
   203  
   204  	if l >= comparison {
   205  		return TestPassed, tMsgGtEqMatch(property, l, comparison)
   206  	}
   207  	return TestFailed, tMsgGtEqFail(property, l, comparison)
   208  }