Move FieldsN to utility file and add tests.

This commit is contained in:
Ian Adam Naval 2014-09-04 02:30:52 -04:00
parent 626f119ad9
commit 7fbc8ebc61
6 changed files with 118 additions and 52 deletions

13
common_test.go Normal file
View File

@ -0,0 +1,13 @@
package jsh
import "testing"
func TestToJson(t *testing.T) {
fixture := JshOutput{[]string{}, []string{}}
json := fixture.ToJson()
expected := "{\"StdOut\":[],\"StdErr\":[]}"
actual := *json
if actual != expected {
t.Error("Empty fixture did not match:\n%s != %s", expected, actual)
}
}

28
process_test.go Normal file
View File

@ -0,0 +1,28 @@
package jsh
import "testing"
func TestNewProcess(t *testing.T) {
tooManyArgs := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}
_, err := NewProcess(tooManyArgs)
if err == nil {
t.Errorf("Passing 12 strings should raise an error")
}
tooFewArgs := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
_, err = NewProcess(tooFewArgs)
if err == nil {
t.Errorf("Passing 10 strings should raise an error")
}
justRightArgs := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}
proc, err := NewProcess(justRightArgs)
if err != nil {
t.Errorf("Passing 11 strings should not raise an error")
}
expected := Process{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}
actual := *proc
if expected != actual {
t.Errorf("Proc was incorrectly generated:\n%s != %s", expected, actual)
}
}

View File

@ -4,49 +4,25 @@ import (
"flag"
"fmt"
"jsh"
"math"
"os"
"os/exec"
"strings"
"unicode"
)
// FieldsN slices s into substrings after each instance of a whitespace
// character (according to unicode.IsSpace) and returns a slice of those
// substrings. The slice's length is guaranteed to be at most maxN, and
// all leftover fields are put into the last substring.
func FieldsN(s string, maxN int) []string {
// First count the fields.
n := 0
inField := false
for _, rune := range s {
wasInField := inField
inField = !unicode.IsSpace(rune)
if inField && !wasInField {
n++
}
}
n = int(math.Min(float64(n), float64(maxN)))
// Converts raw output of "ps" into a slice of Process objects
func PsOutputToProcesses(out string) *[]jsh.Process {
processes := []jsh.Process{}
lines := strings.Split(out, "\n")
header, procs := lines[0], lines[1:]
numFields := len(strings.Fields(header))
// Now create them.
a := make([]string, n)
na := 0
fieldStart := -1 // Set to -1 when looking for start of field.
for i, rune := range s {
if unicode.IsSpace(rune) && na+1 < maxN {
if fieldStart >= 0 {
a[na] = s[fieldStart:i]
na++
fieldStart = -1
}
} else if fieldStart == -1 {
fieldStart = i
for _, proc := range procs {
p, err := jsh.NewProcess(jsh.FieldsN(proc, numFields))
if err == nil {
processes = append(processes, *p)
}
}
if fieldStart >= 0 { // Last field might end at EOF.
a[na] = s[fieldStart:]
}
return a
return &processes
}
// Falls back to procps-ng passing the space-separated arguments in the given
@ -68,27 +44,11 @@ func fallbackCompletely() *[]byte {
return fallbackCompletelyWithArgs(nil)
}
// Converts raw output of "ps" into a slice of Process objects
func psOutputToProcesses(out string) *[]jsh.Process {
processes := []jsh.Process{}
lines := strings.Split(out, "\n")
header, procs := lines[0], lines[1:]
numFields := len(strings.Fields(header))
for _, proc := range procs {
p, err := jsh.NewProcess(FieldsN(proc, numFields))
if err == nil {
processes = append(processes, *p)
}
}
return &processes
}
func runJsonMode() {
// Run procps-ng "ps" with full output
psOut := string(*fallbackCompletelyWithArgs([]string{"auxww"}))
processesPtr := psOutputToProcesses(psOut)
processesPtr := PsOutputToProcesses(psOut)
finalOut := jsh.JshOutput{*processesPtr, []string{}}
fmt.Printf("%s", *finalOut.ToJson())
}

7
ps/main_test.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "testing"
func TestPsOutputToProcesses(t *testing.T) {
}

44
utils.go Normal file
View File

@ -0,0 +1,44 @@
package jsh
import (
"math"
"unicode"
)
// FieldsN slices s into substrings after each instance of a whitespace
// character (according to unicode.IsSpace) and returns a slice of those
// substrings. The slice's length is guaranteed to be at most maxN, and
// all leftover fields are put into the last substring.
func FieldsN(s string, maxN int) []string {
// First count the fields.
n := 0
inField := false
for _, rune := range s {
wasInField := inField
inField = !unicode.IsSpace(rune)
if inField && !wasInField {
n++
}
}
n = int(math.Min(float64(n), float64(maxN)))
// Now create them.
a := make([]string, n)
na := 0
fieldStart := -1 // Set to -1 when looking for start of field.
for i, rune := range s {
if unicode.IsSpace(rune) && na+1 < maxN {
if fieldStart >= 0 {
a[na] = s[fieldStart:i]
na++
fieldStart = -1
}
} else if fieldStart == -1 {
fieldStart = i
}
}
if fieldStart >= 0 { // Last field might end at EOF.
a[na] = s[fieldStart:]
}
return a
}

14
utils_test.go Normal file
View File

@ -0,0 +1,14 @@
package jsh
import "testing"
func TestFieldsN(t *testing.T) {
testString := "Potatoes are the best strings for testing."
for i := 1; i <= 10; i++ {
fields := FieldsN(testString, i)
fieldsLength := len(fields)
if fieldsLength > i {
t.Errorf("Expected at most %d fields, got %d", i, fieldsLength)
}
}
}