github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/testutil/paddedchecker.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2015-2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package testutil
    21  
    22  import (
    23  	"fmt"
    24  	"regexp"
    25  	"strings"
    26  
    27  	"gopkg.in/check.v1"
    28  )
    29  
    30  type paddedChecker struct {
    31  	*check.CheckerInfo
    32  	isRegexp  bool
    33  	isPartial bool
    34  	isLine    bool
    35  }
    36  
    37  // EqualsPadded is a Checker that looks for an expected string to
    38  // be equal to another except that the other might have been padded
    39  // out to align with something else (so arbitrary amounts of
    40  // horizontal whitespace is ok at the ends, and between non-whitespace
    41  // bits).
    42  var EqualsPadded = &paddedChecker{
    43  	CheckerInfo: &check.CheckerInfo{Name: "EqualsPadded", Params: []string{"padded", "expected"}},
    44  	isLine:      true,
    45  }
    46  
    47  // MatchesPadded is a Checker that looks for an expected regexp in
    48  // a string that might have been padded out to align with something
    49  // else (so whitespace in the regexp is changed to [ \t]+, and ^[ \t]*
    50  // is added to the beginning, and [ \t]*$ to the end of it).
    51  var MatchesPadded = &paddedChecker{
    52  	CheckerInfo: &check.CheckerInfo{Name: "MatchesPadded", Params: []string{"padded", "expected"}},
    53  	isRegexp:    true,
    54  	isLine:      true,
    55  }
    56  
    57  // ContainsPadded is a Checker that looks for an expected string
    58  // in another that might have been padded out to align with something
    59  // else (so arbitrary amounts of horizontal whitespace is ok between
    60  // non-whitespace bits).
    61  var ContainsPadded = &paddedChecker{
    62  	CheckerInfo: &check.CheckerInfo{Name: "ContainsPadded", Params: []string{"padded", "expected"}},
    63  	isPartial:   true,
    64  	isLine:      true,
    65  }
    66  
    67  // EqualsWrapped is a Checker that looks for an expected string to be
    68  // equal to another except that the other might have been padded out
    69  // and wrapped (so arbitrary amounts of whitespace is ok at the ends,
    70  // and between non-whitespace bits).
    71  var EqualsWrapped = &paddedChecker{
    72  	CheckerInfo: &check.CheckerInfo{Name: "EqualsWrapped", Params: []string{"wrapped", "expected"}},
    73  }
    74  
    75  // MatchesWrapped is a Checker that looks for an expected regexp in a
    76  // string that might have been padded and wrapped (so whitespace in
    77  // the regexp is changed to \s+, and (?s)^\s* is added to the
    78  // beginning, and \s*$ to the end of it).
    79  var MatchesWrapped = &paddedChecker{
    80  	CheckerInfo: &check.CheckerInfo{Name: "MatchesWrapped", Params: []string{"wrapped", "expected"}},
    81  	isRegexp:    true,
    82  }
    83  
    84  // ContainsWrapped is a Checker that looks for an expected string in
    85  // another that might have been padded out and wrapped (so arbitrary
    86  // amounts of whitespace is ok between non-whitespace bits).
    87  var ContainsWrapped = &paddedChecker{
    88  	CheckerInfo: &check.CheckerInfo{Name: "EqualsWrapped", Params: []string{"wrapped", "expected"}},
    89  	isRegexp:    false,
    90  	isPartial:   true,
    91  }
    92  
    93  var spaceinator = regexp.MustCompile(`\s+`).ReplaceAllLiteralString
    94  
    95  func (c *paddedChecker) Check(params []interface{}, names []string) (result bool, errstr string) {
    96  	var other string
    97  	switch v := params[0].(type) {
    98  	case string:
    99  		other = v
   100  	case []byte:
   101  		other = string(v)
   102  	case error:
   103  		if v != nil {
   104  			other = v.Error()
   105  		}
   106  	default:
   107  		return false, "left-hand value must be a string or []byte or error"
   108  	}
   109  	expected, ok := params[1].(string)
   110  	if !ok {
   111  		ebuf, ok := params[1].([]byte)
   112  		if !ok {
   113  			return false, "right-hand value must be a string or []byte"
   114  		}
   115  		expected = string(ebuf)
   116  	}
   117  	ws := `\s`
   118  	if c.isLine {
   119  		ws = `[\t ]`
   120  	}
   121  	if c.isRegexp {
   122  		_, err := regexp.Compile(expected)
   123  		if err != nil {
   124  			return false, fmt.Sprintf("right-hand value must be a valid regexp: %v", err)
   125  		}
   126  		expected = spaceinator(expected, ws+"+")
   127  	} else {
   128  		fields := strings.Fields(expected)
   129  		for i := range fields {
   130  			fields[i] = regexp.QuoteMeta(fields[i])
   131  		}
   132  		expected = strings.Join(fields, ws+"+")
   133  	}
   134  	if !c.isPartial {
   135  		expected = "^" + ws + "*" + expected + ws + "*$"
   136  	}
   137  	if !c.isLine {
   138  		expected = "(?s)" + expected
   139  	}
   140  
   141  	matches, err := regexp.MatchString(expected, other)
   142  	if err != nil {
   143  		// can't happen (really)
   144  		panic(err)
   145  	}
   146  	return matches, ""
   147  }