Move FieldsN to utility file and add tests.
This commit is contained in:
parent
626f119ad9
commit
7fbc8ebc61
13
common_test.go
Normal file
13
common_test.go
Normal 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
28
process_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
64
ps/main.go
64
ps/main.go
@ -4,49 +4,25 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"jsh"
|
"jsh"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FieldsN slices s into substrings after each instance of a whitespace
|
// Converts raw output of "ps" into a slice of Process objects
|
||||||
// character (according to unicode.IsSpace) and returns a slice of those
|
func PsOutputToProcesses(out string) *[]jsh.Process {
|
||||||
// substrings. The slice's length is guaranteed to be at most maxN, and
|
processes := []jsh.Process{}
|
||||||
// all leftover fields are put into the last substring.
|
lines := strings.Split(out, "\n")
|
||||||
func FieldsN(s string, maxN int) []string {
|
header, procs := lines[0], lines[1:]
|
||||||
// First count the fields.
|
numFields := len(strings.Fields(header))
|
||||||
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.
|
for _, proc := range procs {
|
||||||
a := make([]string, n)
|
p, err := jsh.NewProcess(jsh.FieldsN(proc, numFields))
|
||||||
na := 0
|
if err == nil {
|
||||||
fieldStart := -1 // Set to -1 when looking for start of field.
|
processes = append(processes, *p)
|
||||||
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.
|
return &processes
|
||||||
a[na] = s[fieldStart:]
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Falls back to procps-ng passing the space-separated arguments in the given
|
// Falls back to procps-ng passing the space-separated arguments in the given
|
||||||
@ -68,27 +44,11 @@ func fallbackCompletely() *[]byte {
|
|||||||
return fallbackCompletelyWithArgs(nil)
|
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() {
|
func runJsonMode() {
|
||||||
// Run procps-ng "ps" with full output
|
// Run procps-ng "ps" with full output
|
||||||
psOut := string(*fallbackCompletelyWithArgs([]string{"auxww"}))
|
psOut := string(*fallbackCompletelyWithArgs([]string{"auxww"}))
|
||||||
|
|
||||||
processesPtr := psOutputToProcesses(psOut)
|
processesPtr := PsOutputToProcesses(psOut)
|
||||||
finalOut := jsh.JshOutput{*processesPtr, []string{}}
|
finalOut := jsh.JshOutput{*processesPtr, []string{}}
|
||||||
fmt.Printf("%s", *finalOut.ToJson())
|
fmt.Printf("%s", *finalOut.ToJson())
|
||||||
}
|
}
|
||||||
|
7
ps/main_test.go
Normal file
7
ps/main_test.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestPsOutputToProcesses(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
44
utils.go
Normal file
44
utils.go
Normal 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
14
utils_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user