2016-06-21 02:50:40 +02:00
// Copyright 2016 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package properties
import (
"bytes"
"flag"
"fmt"
"math"
"os"
"strings"
"testing"
"time"
. "github.com/magiconair/properties/_third_party/gopkg.in/check.v1"
)
func Test ( t * testing . T ) { TestingT ( t ) }
type TestSuite struct {
prevHandler ErrorHandlerFunc
}
var (
_ = Suite ( & TestSuite { } )
verbose = flag . Bool ( "verbose" , false , "Verbose output" )
)
// --------------------------------------------------------------------
func ( s * TestSuite ) SetUpSuite ( c * C ) {
s . prevHandler = ErrorHandler
ErrorHandler = PanicHandler
}
// --------------------------------------------------------------------
func ( s * TestSuite ) TearDownSuite ( c * C ) {
ErrorHandler = s . prevHandler
}
// ----------------------------------------------------------------------------
// define test cases in the form of
// {"input", "key1", "value1", "key2", "value2", ...}
var complexTests = [ ] [ ] string {
// whitespace prefix
{ " key=value" , "key" , "value" } , // SPACE prefix
{ "\fkey=value" , "key" , "value" } , // FF prefix
{ "\tkey=value" , "key" , "value" } , // TAB prefix
{ " \f\tkey=value" , "key" , "value" } , // mix prefix
// multiple keys
{ "key1=value1\nkey2=value2\n" , "key1" , "value1" , "key2" , "value2" } ,
{ "key1=value1\rkey2=value2\r" , "key1" , "value1" , "key2" , "value2" } ,
{ "key1=value1\r\nkey2=value2\r\n" , "key1" , "value1" , "key2" , "value2" } ,
// blank lines
{ "\nkey=value\n" , "key" , "value" } ,
{ "\rkey=value\r" , "key" , "value" } ,
{ "\r\nkey=value\r\n" , "key" , "value" } ,
// escaped chars in key
{ "k\\ ey = value" , "k ey" , "value" } ,
{ "k\\:ey = value" , "k:ey" , "value" } ,
{ "k\\=ey = value" , "k=ey" , "value" } ,
{ "k\\fey = value" , "k\fey" , "value" } ,
{ "k\\ney = value" , "k\ney" , "value" } ,
{ "k\\rey = value" , "k\rey" , "value" } ,
{ "k\\tey = value" , "k\tey" , "value" } ,
// escaped chars in value
{ "key = v\\ alue" , "key" , "v alue" } ,
{ "key = v\\:alue" , "key" , "v:alue" } ,
{ "key = v\\=alue" , "key" , "v=alue" } ,
{ "key = v\\falue" , "key" , "v\falue" } ,
{ "key = v\\nalue" , "key" , "v\nalue" } ,
{ "key = v\\ralue" , "key" , "v\ralue" } ,
{ "key = v\\talue" , "key" , "v\talue" } ,
// silently dropped escape character
{ "k\\zey = value" , "kzey" , "value" } ,
{ "key = v\\zalue" , "key" , "vzalue" } ,
// unicode literals
{ "key\\u2318 = value" , "key⌘" , "value" } ,
{ "k\\u2318ey = value" , "k⌘ey" , "value" } ,
{ "key = value\\u2318" , "key" , "value⌘" } ,
{ "key = valu\\u2318e" , "key" , "valu⌘e" } ,
// multiline values
{ "key = valueA,\\\n valueB" , "key" , "valueA,valueB" } , // SPACE indent
{ "key = valueA,\\\n\f\f\fvalueB" , "key" , "valueA,valueB" } , // FF indent
{ "key = valueA,\\\n\t\t\tvalueB" , "key" , "valueA,valueB" } , // TAB indent
{ "key = valueA,\\\n \f\tvalueB" , "key" , "valueA,valueB" } , // mix indent
// comments
{ "# this is a comment\n! and so is this\nkey1=value1\nkey#2=value#2\n\nkey!3=value!3\n# and another one\n! and the final one" , "key1" , "value1" , "key#2" , "value#2" , "key!3" , "value!3" } ,
// expansion tests
{ "key=value\nkey2=${key}" , "key" , "value" , "key2" , "value" } ,
{ "key=value\nkey2=aa${key}" , "key" , "value" , "key2" , "aavalue" } ,
{ "key=value\nkey2=${key}bb" , "key" , "value" , "key2" , "valuebb" } ,
{ "key=value\nkey2=aa${key}bb" , "key" , "value" , "key2" , "aavaluebb" } ,
{ "key=value\nkey2=${key}\nkey3=${key2}" , "key" , "value" , "key2" , "value" , "key3" , "value" } ,
{ "key=${USER}" , "key" , os . Getenv ( "USER" ) } ,
{ "key=${USER}\nUSER=value" , "key" , "value" , "USER" , "value" } ,
}
// ----------------------------------------------------------------------------
var commentTests = [ ] struct {
input , key , value string
comments [ ] string
} {
{ "key=value" , "key" , "value" , nil } ,
{ "#\nkey=value" , "key" , "value" , [ ] string { "" } } ,
{ "#comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "# comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "# comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "# comment\n\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "# comment1\n# comment2\nkey=value" , "key" , "value" , [ ] string { "comment1" , "comment2" } } ,
{ "# comment1\n\n# comment2\n\nkey=value" , "key" , "value" , [ ] string { "comment1" , "comment2" } } ,
{ "!comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "! comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "! comment\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "! comment\n\nkey=value" , "key" , "value" , [ ] string { "comment" } } ,
{ "! comment1\n! comment2\nkey=value" , "key" , "value" , [ ] string { "comment1" , "comment2" } } ,
{ "! comment1\n\n! comment2\n\nkey=value" , "key" , "value" , [ ] string { "comment1" , "comment2" } } ,
}
// ----------------------------------------------------------------------------
var errorTests = [ ] struct {
input , msg string
} {
// unicode literals
{ "key\\u1 = value" , "invalid unicode literal" } ,
{ "key\\u12 = value" , "invalid unicode literal" } ,
{ "key\\u123 = value" , "invalid unicode literal" } ,
{ "key\\u123g = value" , "invalid unicode literal" } ,
{ "key\\u123" , "invalid unicode literal" } ,
// circular references
{ "key=${key}" , "circular reference" } ,
{ "key1=${key2}\nkey2=${key1}" , "circular reference" } ,
// malformed expressions
{ "key=${ke" , "malformed expression" } ,
{ "key=valu${ke" , "malformed expression" } ,
}
// ----------------------------------------------------------------------------
var writeTests = [ ] struct {
input , output , encoding string
} {
// ISO-8859-1 tests
{ "key = value" , "key = value\n" , "ISO-8859-1" } ,
{ "key = value \\\n continued" , "key = value continued\n" , "ISO-8859-1" } ,
{ "key⌘ = value" , "key\\u2318 = value\n" , "ISO-8859-1" } ,
{ "ke\\ \\:y = value" , "ke\\ \\:y = value\n" , "ISO-8859-1" } ,
// UTF-8 tests
{ "key = value" , "key = value\n" , "UTF-8" } ,
{ "key = value \\\n continued" , "key = value continued\n" , "UTF-8" } ,
{ "key⌘ = value⌘" , "key⌘ = value⌘\n" , "UTF-8" } ,
{ "ke\\ \\:y = value" , "ke\\ \\:y = value\n" , "UTF-8" } ,
}
// ----------------------------------------------------------------------------
var writeCommentTests = [ ] struct {
input , output , encoding string
} {
// ISO-8859-1 tests
{ "key = value" , "key = value\n" , "ISO-8859-1" } ,
{ "#\nkey = value" , "key = value\n" , "ISO-8859-1" } ,
{ "#\n#\n#\nkey = value" , "key = value\n" , "ISO-8859-1" } ,
{ "# comment\nkey = value" , "# comment\nkey = value\n" , "ISO-8859-1" } ,
{ "\n# comment\nkey = value" , "# comment\nkey = value\n" , "ISO-8859-1" } ,
{ "# comment\n\nkey = value" , "# comment\nkey = value\n" , "ISO-8859-1" } ,
{ "# comment1\n# comment2\nkey = value" , "# comment1\n# comment2\nkey = value\n" , "ISO-8859-1" } ,
{ "#comment1\nkey1 = value1\n#comment2\nkey2 = value2" , "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n" , "ISO-8859-1" } ,
// UTF-8 tests
{ "key = value" , "key = value\n" , "UTF-8" } ,
{ "# comment⌘\nkey = value⌘" , "# comment⌘\nkey = value⌘\n" , "UTF-8" } ,
{ "\n# comment⌘\nkey = value⌘" , "# comment⌘\nkey = value⌘\n" , "UTF-8" } ,
{ "# comment⌘\n\nkey = value⌘" , "# comment⌘\nkey = value⌘\n" , "UTF-8" } ,
{ "# comment1⌘\n# comment2⌘\nkey = value⌘" , "# comment1⌘\n# comment2⌘\nkey = value⌘\n" , "UTF-8" } ,
{ "#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘" , "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n" , "UTF-8" } ,
}
// ----------------------------------------------------------------------------
var boolTests = [ ] struct {
input , key string
def , value bool
} {
// valid values for TRUE
{ "key = 1" , "key" , false , true } ,
{ "key = on" , "key" , false , true } ,
{ "key = On" , "key" , false , true } ,
{ "key = ON" , "key" , false , true } ,
{ "key = true" , "key" , false , true } ,
{ "key = True" , "key" , false , true } ,
{ "key = TRUE" , "key" , false , true } ,
{ "key = yes" , "key" , false , true } ,
{ "key = Yes" , "key" , false , true } ,
{ "key = YES" , "key" , false , true } ,
// valid values for FALSE (all other)
{ "key = 0" , "key" , true , false } ,
{ "key = off" , "key" , true , false } ,
{ "key = false" , "key" , true , false } ,
{ "key = no" , "key" , true , false } ,
// non existent key
{ "key = true" , "key2" , false , false } ,
}
// ----------------------------------------------------------------------------
var durationTests = [ ] struct {
input , key string
def , value time . Duration
} {
// valid values
{ "key = 1" , "key" , 999 , 1 } ,
{ "key = 0" , "key" , 999 , 0 } ,
{ "key = -1" , "key" , 999 , - 1 } ,
{ "key = 0123" , "key" , 999 , 123 } ,
// invalid values
{ "key = 0xff" , "key" , 999 , 999 } ,
{ "key = 1.0" , "key" , 999 , 999 } ,
{ "key = a" , "key" , 999 , 999 } ,
// non existent key
{ "key = 1" , "key2" , 999 , 999 } ,
}
// ----------------------------------------------------------------------------
var parsedDurationTests = [ ] struct {
input , key string
def , value time . Duration
} {
// valid values
{ "key = -1ns" , "key" , 999 , - 1 * time . Nanosecond } ,
{ "key = 300ms" , "key" , 999 , 300 * time . Millisecond } ,
{ "key = 5s" , "key" , 999 , 5 * time . Second } ,
{ "key = 3h" , "key" , 999 , 3 * time . Hour } ,
{ "key = 2h45m" , "key" , 999 , 2 * time . Hour + 45 * time . Minute } ,
// invalid values
{ "key = 0xff" , "key" , 999 , 999 } ,
{ "key = 1.0" , "key" , 999 , 999 } ,
{ "key = a" , "key" , 999 , 999 } ,
{ "key = 1" , "key" , 999 , 999 } ,
{ "key = 0" , "key" , 999 , 0 } ,
// non existent key
{ "key = 1" , "key2" , 999 , 999 } ,
}
// ----------------------------------------------------------------------------
var floatTests = [ ] struct {
input , key string
def , value float64
} {
// valid values
{ "key = 1.0" , "key" , 999 , 1.0 } ,
{ "key = 0.0" , "key" , 999 , 0.0 } ,
{ "key = -1.0" , "key" , 999 , - 1.0 } ,
{ "key = 1" , "key" , 999 , 1 } ,
{ "key = 0" , "key" , 999 , 0 } ,
{ "key = -1" , "key" , 999 , - 1 } ,
{ "key = 0123" , "key" , 999 , 123 } ,
// invalid values
{ "key = 0xff" , "key" , 999 , 999 } ,
{ "key = a" , "key" , 999 , 999 } ,
// non existent key
{ "key = 1" , "key2" , 999 , 999 } ,
}
// ----------------------------------------------------------------------------
var int64Tests = [ ] struct {
input , key string
def , value int64
} {
// valid values
{ "key = 1" , "key" , 999 , 1 } ,
{ "key = 0" , "key" , 999 , 0 } ,
{ "key = -1" , "key" , 999 , - 1 } ,
{ "key = 0123" , "key" , 999 , 123 } ,
// invalid values
{ "key = 0xff" , "key" , 999 , 999 } ,
{ "key = 1.0" , "key" , 999 , 999 } ,
{ "key = a" , "key" , 999 , 999 } ,
// non existent key
{ "key = 1" , "key2" , 999 , 999 } ,
}
// ----------------------------------------------------------------------------
var uint64Tests = [ ] struct {
input , key string
def , value uint64
} {
// valid values
{ "key = 1" , "key" , 999 , 1 } ,
{ "key = 0" , "key" , 999 , 0 } ,
{ "key = 0123" , "key" , 999 , 123 } ,
// invalid values
{ "key = -1" , "key" , 999 , 999 } ,
{ "key = 0xff" , "key" , 999 , 999 } ,
{ "key = 1.0" , "key" , 999 , 999 } ,
{ "key = a" , "key" , 999 , 999 } ,
// non existent key
{ "key = 1" , "key2" , 999 , 999 } ,
}
// ----------------------------------------------------------------------------
var stringTests = [ ] struct {
input , key string
def , value string
} {
// valid values
{ "key = abc" , "key" , "def" , "abc" } ,
// non existent key
{ "key = abc" , "key2" , "def" , "def" } ,
}
// ----------------------------------------------------------------------------
var keysTests = [ ] struct {
input string
keys [ ] string
} {
{ "" , [ ] string { } } ,
{ "key = abc" , [ ] string { "key" } } ,
{ "key = abc\nkey2=def" , [ ] string { "key" , "key2" } } ,
{ "key2 = abc\nkey=def" , [ ] string { "key2" , "key" } } ,
{ "key = abc\nkey=def" , [ ] string { "key" } } ,
}
// ----------------------------------------------------------------------------
var filterTests = [ ] struct {
input string
pattern string
keys [ ] string
err string
} {
{ "" , "" , [ ] string { } , "" } ,
{ "" , "abc" , [ ] string { } , "" } ,
{ "key=value" , "" , [ ] string { "key" } , "" } ,
{ "key=value" , "key=" , [ ] string { } , "" } ,
{ "key=value\nfoo=bar" , "" , [ ] string { "foo" , "key" } , "" } ,
{ "key=value\nfoo=bar" , "f" , [ ] string { "foo" } , "" } ,
{ "key=value\nfoo=bar" , "fo" , [ ] string { "foo" } , "" } ,
{ "key=value\nfoo=bar" , "foo" , [ ] string { "foo" } , "" } ,
{ "key=value\nfoo=bar" , "fooo" , [ ] string { } , "" } ,
{ "key=value\nkey2=value2\nfoo=bar" , "ey" , [ ] string { "key" , "key2" } , "" } ,
{ "key=value\nkey2=value2\nfoo=bar" , "key" , [ ] string { "key" , "key2" } , "" } ,
{ "key=value\nkey2=value2\nfoo=bar" , "^key" , [ ] string { "key" , "key2" } , "" } ,
{ "key=value\nkey2=value2\nfoo=bar" , "^(key|foo)" , [ ] string { "foo" , "key" , "key2" } , "" } ,
{ "key=value\nkey2=value2\nfoo=bar" , "[ abc" , nil , "error parsing regexp.*" } ,
}
// ----------------------------------------------------------------------------
var filterPrefixTests = [ ] struct {
input string
prefix string
keys [ ] string
} {
{ "" , "" , [ ] string { } } ,
{ "" , "abc" , [ ] string { } } ,
{ "key=value" , "" , [ ] string { "key" } } ,
{ "key=value" , "key=" , [ ] string { } } ,
{ "key=value\nfoo=bar" , "" , [ ] string { "foo" , "key" } } ,
{ "key=value\nfoo=bar" , "f" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "fo" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "foo" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "fooo" , [ ] string { } } ,
{ "key=value\nkey2=value2\nfoo=bar" , "key" , [ ] string { "key" , "key2" } } ,
}
// ----------------------------------------------------------------------------
var filterStripPrefixTests = [ ] struct {
input string
prefix string
keys [ ] string
} {
{ "" , "" , [ ] string { } } ,
{ "" , "abc" , [ ] string { } } ,
{ "key=value" , "" , [ ] string { "key" } } ,
{ "key=value" , "key=" , [ ] string { } } ,
{ "key=value\nfoo=bar" , "" , [ ] string { "foo" , "key" } } ,
{ "key=value\nfoo=bar" , "f" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "fo" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "foo" , [ ] string { "foo" } } ,
{ "key=value\nfoo=bar" , "fooo" , [ ] string { } } ,
{ "key=value\nkey2=value2\nfoo=bar" , "key" , [ ] string { "key" , "key2" } } ,
}
// ----------------------------------------------------------------------------
var setTests = [ ] struct {
input string
key , value string
prev string
ok bool
err string
keys [ ] string
} {
{ "" , "" , "" , "" , false , "" , [ ] string { } } ,
{ "" , "key" , "value" , "" , false , "" , [ ] string { "key" } } ,
{ "key=value" , "key2" , "value2" , "" , false , "" , [ ] string { "key" , "key2" } } ,
{ "key=value" , "abc" , "value3" , "" , false , "" , [ ] string { "key" , "abc" } } ,
{ "key=value" , "key" , "value3" , "value" , true , "" , [ ] string { "key" } } ,
}
// ----------------------------------------------------------------------------
// TestBasic tests basic single key/value combinations with all possible
// whitespace, delimiter and newline permutations.
func ( s * TestSuite ) TestBasic ( c * C ) {
testWhitespaceAndDelimiterCombinations ( c , "key" , "" )
testWhitespaceAndDelimiterCombinations ( c , "key" , "value" )
testWhitespaceAndDelimiterCombinations ( c , "key" , "value " )
}
func ( s * TestSuite ) TestComplex ( c * C ) {
for _ , test := range complexTests {
testKeyValue ( c , test [ 0 ] , test [ 1 : ] ... )
}
}
func ( s * TestSuite ) TestErrors ( c * C ) {
for _ , test := range errorTests {
_ , err := Load ( [ ] byte ( test . input ) , ISO_8859_1 )
c . Assert ( err , NotNil )
c . Assert ( strings . Contains ( err . Error ( ) , test . msg ) , Equals , true , Commentf ( "Expected %q got %q" , test . msg , err . Error ( ) ) )
}
}
func ( s * TestSuite ) TestDisableExpansion ( c * C ) {
input := "key=value\nkey2=${key}"
p , err := parse ( input )
p . DisableExpansion = true
c . Assert ( err , IsNil )
c . Assert ( p . MustGet ( "key" ) , Equals , "value" )
c . Assert ( p . MustGet ( "key2" ) , Equals , "${key}" )
// with expansion disabled we can introduce circular references
p . Set ( "keyA" , "${keyB}" )
p . Set ( "keyB" , "${keyA}" )
c . Assert ( p . MustGet ( "keyA" ) , Equals , "${keyB}" )
c . Assert ( p . MustGet ( "keyB" ) , Equals , "${keyA}" )
}
func ( s * TestSuite ) TestMustGet ( c * C ) {
input := "key = value\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGet ( "key" ) , Equals , "value" )
c . Assert ( func ( ) { p . MustGet ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetBool ( c * C ) {
for _ , test := range boolTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetBool ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetBool ( c * C ) {
input := "key = true\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetBool ( "key" ) , Equals , true )
c . Assert ( func ( ) { p . MustGetBool ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetDuration ( c * C ) {
for _ , test := range durationTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetDuration ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetDuration ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetDuration ( "key" ) , Equals , time . Duration ( 123 ) )
c . Assert ( func ( ) { p . MustGetDuration ( "key2" ) } , PanicMatches , "strconv.ParseInt: parsing.*" )
c . Assert ( func ( ) { p . MustGetDuration ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetParsedDuration ( c * C ) {
for _ , test := range parsedDurationTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetParsedDuration ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetParsedDuration ( c * C ) {
input := "key = 123ms\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetParsedDuration ( "key" ) , Equals , 123 * time . Millisecond )
c . Assert ( func ( ) { p . MustGetParsedDuration ( "key2" ) } , PanicMatches , "time: invalid duration ghi" )
c . Assert ( func ( ) { p . MustGetParsedDuration ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetFloat64 ( c * C ) {
for _ , test := range floatTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetFloat64 ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetFloat64 ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetFloat64 ( "key" ) , Equals , float64 ( 123 ) )
c . Assert ( func ( ) { p . MustGetFloat64 ( "key2" ) } , PanicMatches , "strconv.ParseFloat: parsing.*" )
c . Assert ( func ( ) { p . MustGetFloat64 ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetInt ( c * C ) {
for _ , test := range int64Tests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetInt ( test . key , int ( test . def ) ) , Equals , int ( test . value ) )
}
}
func ( s * TestSuite ) TestMustGetInt ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetInt ( "key" ) , Equals , int ( 123 ) )
c . Assert ( func ( ) { p . MustGetInt ( "key2" ) } , PanicMatches , "strconv.ParseInt: parsing.*" )
c . Assert ( func ( ) { p . MustGetInt ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetInt64 ( c * C ) {
for _ , test := range int64Tests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetInt64 ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetInt64 ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetInt64 ( "key" ) , Equals , int64 ( 123 ) )
c . Assert ( func ( ) { p . MustGetInt64 ( "key2" ) } , PanicMatches , "strconv.ParseInt: parsing.*" )
c . Assert ( func ( ) { p . MustGetInt64 ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetUint ( c * C ) {
for _ , test := range uint64Tests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetUint ( test . key , uint ( test . def ) ) , Equals , uint ( test . value ) )
}
}
func ( s * TestSuite ) TestMustGetUint ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetUint ( "key" ) , Equals , uint ( 123 ) )
c . Assert ( func ( ) { p . MustGetUint64 ( "key2" ) } , PanicMatches , "strconv.ParseUint: parsing.*" )
c . Assert ( func ( ) { p . MustGetUint64 ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetUint64 ( c * C ) {
for _ , test := range uint64Tests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetUint64 ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetUint64 ( c * C ) {
input := "key = 123\nkey2 = ghi"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetUint64 ( "key" ) , Equals , uint64 ( 123 ) )
c . Assert ( func ( ) { p . MustGetUint64 ( "key2" ) } , PanicMatches , "strconv.ParseUint: parsing.*" )
c . Assert ( func ( ) { p . MustGetUint64 ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestGetString ( c * C ) {
for _ , test := range stringTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , 1 )
c . Assert ( p . GetString ( test . key , test . def ) , Equals , test . value )
}
}
func ( s * TestSuite ) TestMustGetString ( c * C ) {
input := ` key = value `
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetString ( "key" ) , Equals , "value" )
c . Assert ( func ( ) { p . MustGetString ( "invalid" ) } , PanicMatches , "unknown property: invalid" )
}
func ( s * TestSuite ) TestComment ( c * C ) {
for _ , test := range commentTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetString ( test . key ) , Equals , test . value )
c . Assert ( p . GetComments ( test . key ) , DeepEquals , test . comments )
if test . comments != nil {
c . Assert ( p . GetComment ( test . key ) , Equals , test . comments [ len ( test . comments ) - 1 ] )
} else {
c . Assert ( p . GetComment ( test . key ) , Equals , "" )
}
// test setting comments
if len ( test . comments ) > 0 {
// set single comment
p . ClearComments ( )
c . Assert ( len ( p . c ) , Equals , 0 )
p . SetComment ( test . key , test . comments [ 0 ] )
c . Assert ( p . GetComment ( test . key ) , Equals , test . comments [ 0 ] )
// set multiple comments
p . ClearComments ( )
c . Assert ( len ( p . c ) , Equals , 0 )
p . SetComments ( test . key , test . comments )
c . Assert ( p . GetComments ( test . key ) , DeepEquals , test . comments )
// clear comments for a key
p . SetComments ( test . key , nil )
c . Assert ( p . GetComment ( test . key ) , Equals , "" )
c . Assert ( p . GetComments ( test . key ) , IsNil )
}
}
}
func ( s * TestSuite ) TestFilter ( c * C ) {
for _ , test := range filterTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
pp , err := p . Filter ( test . pattern )
if err != nil {
c . Assert ( err , ErrorMatches , test . err )
continue
}
c . Assert ( pp , NotNil )
c . Assert ( pp . Len ( ) , Equals , len ( test . keys ) )
for _ , key := range test . keys {
v1 , ok1 := p . Get ( key )
v2 , ok2 := pp . Get ( key )
c . Assert ( ok1 , Equals , true )
c . Assert ( ok2 , Equals , true )
c . Assert ( v1 , Equals , v2 )
}
}
}
func ( s * TestSuite ) TestFilterPrefix ( c * C ) {
for _ , test := range filterPrefixTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
pp := p . FilterPrefix ( test . prefix )
c . Assert ( pp , NotNil )
c . Assert ( pp . Len ( ) , Equals , len ( test . keys ) )
for _ , key := range test . keys {
v1 , ok1 := p . Get ( key )
v2 , ok2 := pp . Get ( key )
c . Assert ( ok1 , Equals , true )
c . Assert ( ok2 , Equals , true )
c . Assert ( v1 , Equals , v2 )
}
}
}
func ( s * TestSuite ) TestKeys ( c * C ) {
for _ , test := range keysTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
c . Assert ( p . Len ( ) , Equals , len ( test . keys ) )
c . Assert ( len ( p . Keys ( ) ) , Equals , len ( test . keys ) )
c . Assert ( p . Keys ( ) , DeepEquals , test . keys )
}
}
func ( s * TestSuite ) TestSet ( c * C ) {
for _ , test := range setTests {
p , err := parse ( test . input )
c . Assert ( err , IsNil )
prev , ok , err := p . Set ( test . key , test . value )
if test . err != "" {
c . Assert ( err , ErrorMatches , test . err )
continue
}
c . Assert ( err , IsNil )
c . Assert ( ok , Equals , test . ok )
if ok {
c . Assert ( prev , Equals , test . prev )
}
c . Assert ( p . Keys ( ) , DeepEquals , test . keys )
}
}
func ( s * TestSuite ) TestMustSet ( c * C ) {
input := "key=${key}"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( func ( ) { p . MustSet ( "key" , "${key}" ) } , PanicMatches , "circular reference .*" )
}
func ( s * TestSuite ) TestWrite ( c * C ) {
for _ , test := range writeTests {
p , err := parse ( test . input )
buf := new ( bytes . Buffer )
var n int
switch test . encoding {
case "UTF-8" :
n , err = p . Write ( buf , UTF8 )
case "ISO-8859-1" :
n , err = p . Write ( buf , ISO_8859_1 )
}
c . Assert ( err , IsNil )
s := string ( buf . Bytes ( ) )
c . Assert ( n , Equals , len ( test . output ) , Commentf ( "input=%q expected=%q obtained=%q" , test . input , test . output , s ) )
c . Assert ( s , Equals , test . output , Commentf ( "input=%q expected=%q obtained=%q" , test . input , test . output , s ) )
}
}
func ( s * TestSuite ) TestWriteComment ( c * C ) {
for _ , test := range writeCommentTests {
p , err := parse ( test . input )
buf := new ( bytes . Buffer )
var n int
switch test . encoding {
case "UTF-8" :
n , err = p . WriteComment ( buf , "# " , UTF8 )
case "ISO-8859-1" :
n , err = p . WriteComment ( buf , "# " , ISO_8859_1 )
}
c . Assert ( err , IsNil )
s := string ( buf . Bytes ( ) )
c . Assert ( n , Equals , len ( test . output ) , Commentf ( "input=%q expected=%q obtained=%q" , test . input , test . output , s ) )
c . Assert ( s , Equals , test . output , Commentf ( "input=%q expected=%q obtained=%q" , test . input , test . output , s ) )
}
}
func ( s * TestSuite ) TestCustomExpansionExpression ( c * C ) {
testKeyValuePrePostfix ( c , "*[" , "]*" , "key=value\nkey2=*[key]*" , "key" , "value" , "key2" , "value" )
}
func ( s * TestSuite ) TestPanicOn32BitIntOverflow ( c * C ) {
is32Bit = true
var min , max int64 = math . MinInt32 - 1 , math . MaxInt32 + 1
input := fmt . Sprintf ( "min=%d\nmax=%d" , min , max )
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetInt64 ( "min" ) , Equals , min )
c . Assert ( p . MustGetInt64 ( "max" ) , Equals , max )
c . Assert ( func ( ) { p . MustGetInt ( "min" ) } , PanicMatches , ".* out of range" )
c . Assert ( func ( ) { p . MustGetInt ( "max" ) } , PanicMatches , ".* out of range" )
}
func ( s * TestSuite ) TestPanicOn32BitUintOverflow ( c * C ) {
is32Bit = true
var max uint64 = math . MaxUint32 + 1
input := fmt . Sprintf ( "max=%d" , max )
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Assert ( p . MustGetUint64 ( "max" ) , Equals , max )
c . Assert ( func ( ) { p . MustGetUint ( "max" ) } , PanicMatches , ".* out of range" )
}
func ( s * TestSuite ) TestDeleteKey ( c * C ) {
input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Check ( len ( p . m ) , Equals , 2 )
c . Check ( len ( p . c ) , Equals , 1 )
c . Check ( len ( p . k ) , Equals , 2 )
p . Delete ( "key" )
c . Check ( len ( p . m ) , Equals , 1 )
c . Check ( len ( p . c ) , Equals , 0 )
c . Check ( len ( p . k ) , Equals , 1 )
}
func ( s * TestSuite ) TestDeleteUnknownKey ( c * C ) {
input := "#comments should also be gone\nkey=to-be-deleted"
p , err := parse ( input )
c . Assert ( err , IsNil )
c . Check ( len ( p . m ) , Equals , 1 )
c . Check ( len ( p . c ) , Equals , 1 )
c . Check ( len ( p . k ) , Equals , 1 )
p . Delete ( "wrong-key" )
c . Check ( len ( p . m ) , Equals , 1 )
c . Check ( len ( p . c ) , Equals , 1 )
c . Check ( len ( p . k ) , Equals , 1 )
}
2016-07-12 01:03:02 +02:00
func ( s * TestSuite ) TestMerge ( c * C ) {
input1 := "#comment\nkey=value\nkey2=value2"
input2 := "#another comment\nkey=another value\nkey3=value3"
p1 , err := parse ( input1 )
c . Assert ( err , IsNil )
p2 , err := parse ( input2 )
p1 . Merge ( p2 )
c . Check ( len ( p1 . m ) , Equals , 3 )
c . Check ( len ( p1 . c ) , Equals , 1 )
c . Check ( len ( p1 . k ) , Equals , 3 )
c . Check ( p1 . MustGet ( "key" ) , Equals , "another value" )
c . Check ( p1 . GetComment ( "key" ) , Equals , "another comment" )
}
2016-06-21 02:50:40 +02:00
// ----------------------------------------------------------------------------
// tests all combinations of delimiters, leading and/or trailing whitespace and newlines.
func testWhitespaceAndDelimiterCombinations ( c * C , key , value string ) {
whitespace := [ ] string { "" , " " , "\f" , "\t" }
delimiters := [ ] string { "" , " " , "=" , ":" }
newlines := [ ] string { "" , "\r" , "\n" , "\r\n" }
for _ , dl := range delimiters {
for _ , ws1 := range whitespace {
for _ , ws2 := range whitespace {
for _ , nl := range newlines {
// skip the one case where there is nothing between a key and a value
if ws1 == "" && dl == "" && ws2 == "" && value != "" {
continue
}
input := fmt . Sprintf ( "%s%s%s%s%s%s" , key , ws1 , dl , ws2 , value , nl )
testKeyValue ( c , input , key , value )
}
}
}
}
}
// tests whether key/value pairs exist for a given input.
// keyvalues is expected to be an even number of strings of "key", "value", ...
func testKeyValue ( c * C , input string , keyvalues ... string ) {
testKeyValuePrePostfix ( c , "${" , "}" , input , keyvalues ... )
}
// tests whether key/value pairs exist for a given input.
// keyvalues is expected to be an even number of strings of "key", "value", ...
func testKeyValuePrePostfix ( c * C , prefix , postfix , input string , keyvalues ... string ) {
printf ( "%q\n" , input )
p , err := Load ( [ ] byte ( input ) , ISO_8859_1 )
c . Assert ( err , IsNil )
p . Prefix = prefix
p . Postfix = postfix
assertKeyValues ( c , input , p , keyvalues ... )
}
// tests whether key/value pairs exist for a given input.
// keyvalues is expected to be an even number of strings of "key", "value", ...
func assertKeyValues ( c * C , input string , p * Properties , keyvalues ... string ) {
c . Assert ( p , NotNil )
c . Assert ( 2 * p . Len ( ) , Equals , len ( keyvalues ) , Commentf ( "Odd number of key/value pairs." ) )
for i := 0 ; i < len ( keyvalues ) ; i += 2 {
key , value := keyvalues [ i ] , keyvalues [ i + 1 ]
v , ok := p . Get ( key )
c . Assert ( ok , Equals , true , Commentf ( "No key %q found (input=%q)" , key , input ) )
c . Assert ( v , Equals , value , Commentf ( "Value %q does not match %q (input=%q)" , v , value , input ) )
}
}
// prints to stderr if the -verbose flag was given.
func printf ( format string , args ... interface { } ) {
if * verbose {
fmt . Fprintf ( os . Stderr , format , args ... )
}
}