Compare commits

...

2 Commits

3 changed files with 95 additions and 1 deletions

View File

@ -84,12 +84,17 @@ var negativeZero = math.Copysign(0, -1)
type Value interface { type Value interface {
value () value ()
fmt.Stringer fmt.Stringer
Equals (Value) bool
} }
// ValueString is a string value. // ValueString is a string value.
type ValueString string type ValueString string
var _ Value = ValueString("") var _ Value = ValueString("")
func (ValueString) value () { } func (ValueString) value () { }
func (value ValueString) Equals (other Value) bool {
other, ok := other.(ValueString)
return ok && value == other
}
func (value ValueString) String () string { func (value ValueString) String () string {
return fmt.Sprintf("\"%s\"", escape(string(value))) return fmt.Sprintf("\"%s\"", escape(string(value)))
} }
@ -98,6 +103,10 @@ func (value ValueString) String () string {
type ValueNumber float64 type ValueNumber float64
var _ Value = ValueNumber(0) var _ Value = ValueNumber(0)
func (ValueNumber) value () { } func (ValueNumber) value () { }
func (value ValueNumber) Equals (other Value) bool {
other, ok := other.(ValueNumber)
return ok && value == other
}
func (value ValueNumber) String () string { func (value ValueNumber) String () string {
number := float64(value) number := float64(value)
// the requirements I wrote said lossless in all cases. here's lossless // the requirements I wrote said lossless in all cases. here's lossless
@ -133,6 +142,10 @@ func (value ValueNumber) String () string {
var _ Value = ValueBool(false) var _ Value = ValueBool(false)
type ValueBool bool type ValueBool bool
func (ValueBool) value () { } func (ValueBool) value () { }
func (value ValueBool) Equals (other Value) bool {
other, ok := other.(ValueBool)
return ok && value == other
}
func (value ValueBool) String () string { func (value ValueBool) String () string {
if value { if value {
return "true" return "true"

View File

@ -143,6 +143,14 @@ func ParseValue (str string) (Value, error) {
} }
} }
// Has returns whether the key exists. If the key is invalid, it returns false,
// ErrMalformedKey.
func (this *File) Has (key string) (bool, error) {
if !KeyValid(key) { return false, ErrMalformedKey }
_, ok := this.keys[key]
return ok, nil
}
// Get gets the keyed value. If the value is unspecified, it returns nil, // Get gets the keyed value. If the value is unspecified, it returns nil,
// ErrNonexistentEntry. If the key is invalid, it returns nil, ErrMalformedKey. // ErrNonexistentEntry. If the key is invalid, it returns nil, ErrMalformedKey.
func (this *File) Get (key string) (Value, error) { func (this *File) Get (key string) (Value, error) {
@ -186,7 +194,7 @@ func (this *File) Reset (key string) error {
return nil return nil
} }
// Map returns a map of keys to values. // Map creates and returns a map of keys to values.
func (this *File) Map () map[string] Value { func (this *File) Map () map[string] Value {
mp := make(map[string] Value) mp := make(map[string] Value)
for key, index := range this.keys { for key, index := range this.keys {
@ -197,6 +205,33 @@ func (this *File) Map () map[string] Value {
return mp return mp
} }
// Diff returns a set of keys that are different from the other file.
func (this *File) Diff (other *File) map[string] struct { } {
diff := make(map[string] struct { })
// - keys only we have
// - keys we both have, but are different
for key, index := range this.keys {
otherIndex, ok := other.keys[key]
if !ok {
diff[key] = struct { } { }
continue
}
if !this.lines[index].(entry).value.Equals(other.lines[otherIndex].(entry).value) {
diff[key] = struct { } { }
}
}
// - keys only they have
for key := range other.keys {
if _, has := this.keys[key]; !has {
diff[key] = struct { } { }
}
}
return diff
}
// WriteTo writes the data in this file to an io.Writer. // WriteTo writes the data in this file to an io.Writer.
func (file *File) WriteTo (writer io.Writer) (n int64, err error) { func (file *File) WriteTo (writer io.Writer) (n int64, err error) {
for _, lin := range file.lines { for _, lin := range file.lines {

View File

@ -1,6 +1,7 @@
package config package config
import "math" import "math"
import "maps"
import "strings" import "strings"
import "testing" import "testing"
@ -103,6 +104,51 @@ key1=7
`) `)
} }
func TestDiffNone (test *testing.T) {
str := `
thing = something
otherThing = otherValue
# comment
otherThing = true
otherThing = 234
yetAnotherThing = 0.23498
`
file1 := parseFileString(test, str)
file2 := parseFileString(test, str)
diff := file1.Diff(file2)
if len(diff) != 0 {
test.Fatalf("diff not empty:\n%v", diff)
}
}
func TestDiff (test *testing.T) {
file1 := parseFileString(test,
`key4=0
key1=value1
# comment
key2=34`)
file2 := parseFileString(test,
`key1=value2
key2=34
# comment
key3=0.2`)
diff := file1.Diff(file2)
correct := map[string] struct { } {
"key1": struct { } { },
"key3": struct { } { },
"key4": struct { } { },
}
if !maps.Equal(diff, correct) {
test.Error("diffs do not match")
test.Errorf("EXPECTED:\n%v", correct)
test.Errorf("GOT:\n%v", diff)
test.Fail()
}
}
func testParseEntry (test *testing.T, str string, key string, value Value) { func testParseEntry (test *testing.T, str string, key string, value Value) {
ent, err := parseEntry(str) ent, err := parseEntry(str)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }