Pārlūkot izejas kodu

Add parseNumberMenu()

This function is designed to replace the existing number menu
in upcoming commits.
morganamilo 7 gadi atpakaļ
vecāks
revīzija
6988537552
4 mainītis faili ar 212 papildinājumiem un 1 dzēšanām
  1. 105 0
      parser.go
  2. 99 0
      parser_test.go
  3. 7 0
      query.go
  4. 1 1
      vcs_test.go

+ 105 - 0
parser.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"strconv"
 	"strings"
 )
 
@@ -38,6 +39,20 @@ func (set stringSet) toSlice() []string {
 	return slice
 }
 
+func SliceToStringSet(in []string) stringSet {
+	set := make(stringSet)
+
+	for _, v := range in {
+		set.set(v)
+	}
+
+	return set
+}
+
+func makeStringSet(in ...string) stringSet {
+	return SliceToStringSet(in)
+}
+
 // Parses command line arguments in a way we can interact with programmatically but
 // also in a way that can easily be passed to pacman later on.
 type arguments struct {
@@ -554,3 +569,93 @@ func (parser *arguments) parseCommandLine() (err error) {
 
 	return
 }
+
+type intRange struct {
+	min int
+	max int
+}
+
+func makeIntRange(min, max int) intRange {
+	return intRange{
+		min,
+		max,
+	}
+}
+
+func (r intRange) get(n int) bool {
+	return n >= r.min && n <= r.max
+}
+
+type intRanges []intRange
+
+func (rs intRanges) get(n int) bool {
+	for _, r := range rs {
+		if r.get(n) {
+			return true
+		}
+	}
+
+	return false
+}
+
+//parses input for number menus
+//supports individual selection: 1 2 3 4
+//supports range selections: 1-4 10-20
+//supports negation: ^1 ^1-4
+//
+//include and excule holds numbers that should be added and should not be added
+//respectively. other holds anythign that can't be parsed as an int. This is
+//intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
+//of course the implementation is up to the caller, this function mearley parses
+//the input and organizes it
+func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) {
+	include := make(intRanges, 0, 0)
+	exclude := make(intRanges, 0, 0)
+	otherInclude := make(stringSet)
+	otherExclude := make(stringSet)
+
+	words := strings.Fields(input)
+
+	for _, word := range words {
+		var num1 int
+		var num2 int
+		var err error
+		invert := false
+		other := otherInclude
+
+		if word[0] == '^' {
+			invert = true
+			other = otherExclude
+			word = word[1:]
+		}
+
+		ranges := strings.SplitN(word, "-", 2)
+
+		num1, err = strconv.Atoi(ranges[0])
+		if err != nil {
+			other.set(strings.ToLower(word))
+			continue
+		}
+
+		if len(ranges) == 2 {
+			num2, err = strconv.Atoi(ranges[1])
+			if err != nil {
+				other.set(strings.ToLower(word))
+				continue
+			}
+		} else {
+			num2 = num1
+		}
+
+		mi := min(num1, num2)
+		ma := max(num1, num2)
+
+		if !invert {
+			include = append(include, makeIntRange(mi, ma))
+		} else {
+			exclude = append(exclude, makeIntRange(mi, ma))
+		}
+	}
+
+	return include, exclude, otherInclude, otherExclude
+}

+ 99 - 0
parser_test.go

@@ -0,0 +1,99 @@
+package main
+
+import "testing"
+
+func intRangesEqual(a, b intRanges) bool {
+	if a == nil && b == nil {
+		return true
+	}
+
+	if a == nil || b == nil {
+		return false
+	}
+
+	if len(a) != len(b) {
+		return false
+	}
+
+	for n := range a {
+		r1 := a[n]
+		r2 := b[n]
+
+		if r1.min != r1.min || r1.max != r2.max {
+			return false
+		}
+	}
+
+	return true
+}
+
+func stringSetEqual(a, b stringSet) bool {
+	if a == nil && b == nil {
+		return true
+	}
+
+	if a == nil || b == nil {
+		return false
+	}
+
+	if len(a) != len(b) {
+		return false
+	}
+
+	for n := range a {
+		if !b.get(n) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func TestParseNumberMenu(t *testing.T) {
+	type result struct {
+		Include      intRanges
+		Exclude      intRanges
+		OtherInclude stringSet
+		OtherExclude stringSet
+	}
+
+	inputs := []string{
+		"1 2 3 4 5",
+		"1-10 5-15",
+		"10-5 90-85",
+		"1 ^2 ^10-5 99 ^40-38 ^123 60-62",
+		"abort all none",
+		"a-b ^a-b ^abort",
+		"1\t2   3      4\t\t  \t 5",
+		"",
+		"   \t   ",
+		"A B C D E",
+	}
+
+	expected := []result{
+		{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{makeIntRange(1, 10), makeIntRange(5, 15)}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{makeIntRange(5, 10), makeIntRange(85, 90)}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{makeIntRange(1, 1), makeIntRange(99, 99), makeIntRange(60, 62)}, intRanges{makeIntRange(2, 2), makeIntRange(5, 10), makeIntRange(38, 40), makeIntRange(123, 123)}, make(stringSet), make(stringSet)},
+		{intRanges{}, intRanges{}, makeStringSet("abort", "all", "none"), make(stringSet)},
+		{intRanges{}, intRanges{}, makeStringSet("a-b"), makeStringSet("abort", "a-b")},
+		{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
+		{intRanges{}, intRanges{}, makeStringSet("a", "b", "c", "d", "e"), make(stringSet)},
+	}
+
+	for n, in := range inputs {
+		res := expected[n]
+		include, exclude, otherInclude, otherExclude := parseNumberMenu(in)
+
+		if !intRangesEqual(include, res.Include) ||
+			!intRangesEqual(exclude, res.Exclude) ||
+			!stringSetEqual(otherInclude, res.OtherInclude) ||
+			!stringSetEqual(otherExclude, res.OtherExclude) {
+
+			t.Fatalf("Test %d Failed: Expected: include=%+v exclude=%+v otherInclude=%+v otherExclude=%+v got include=%+v excluive=%+v otherInclude=%+v otherExclude=%+v",
+				n+1, res.Include, res.Exclude, res.OtherInclude, res.OtherExclude, include, exclude, otherInclude, otherExclude)
+		}
+	}
+}

+ 7 - 0
query.go

@@ -317,6 +317,13 @@ func min(a, b int) int {
 	return b
 }
 
+func max(a, b int) int {
+	if a < b {
+		return b
+	}
+	return a
+}
+
 // Queries the aur for information about specified packages.
 // All packages should be queried in a single rpc request except when the number
 // of packages exceeds the number set in config.RequestSplitN.

+ 1 - 1
vcs_test.go

@@ -60,7 +60,7 @@ func TestParsing(t *testing.T) {
 			branch != compare.Branch ||
 			!isEqual(protocols, compare.Protocols) {
 
-			t.Fatalf("Expected url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", url, branch, protocols, compare.URL, compare.Branch, compare.Protocols)
+			t.Fatalf("Test %d failed: Expected: url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", n+1, url, branch, protocols, compare.URL, compare.Branch, compare.Protocols)
 		}
 	}