2022-02-01 04:34:17 +00:00
package yqlib
import (
"bufio"
"fmt"
"testing"
"github.com/mikefarah/yq/v4/test"
)
2022-10-28 03:16:46 +00:00
const propertiesWithCommentsOnMap = ` this . thing = hi hi
# important notes
# about this value
this . value = cool
`
const expectedPropertiesWithCommentsOnMapProps = ` this . thing = hi hi
# important notes
# about this value
this . value = cool
`
const expectedPropertiesWithCommentsOnMapYaml = ` this :
thing : hi hi
# important notes
# about this value
value : cool
`
const propertiesWithCommentInArray = `
this . array .0 = cat
# important notes
# about dogs
this . array .1 = dog
`
const expectedPropertiesWithCommentInArrayProps = ` this . array .0 = cat
# important notes
# about dogs
this . array .1 = dog
`
const expectedPropertiesWithCommentInArrayYaml = ` this :
array :
- cat
# important notes
# about dogs
- dog
`
const samplePropertiesYaml = ` # block comments come through
2022-02-01 04:34:17 +00:00
person : # neither do comments on maps
2022-06-25 02:22:03 +00:00
name : Mike Wazowski # comments on values appear
2022-02-01 04:34:17 +00:00
pets :
- cat # comments on array values appear
2024-02-20 00:39:56 +00:00
- nested :
- list entry
2022-02-01 04:34:17 +00:00
food : [ pizza ] # comments on arrays do not
emptyArray : [ ]
emptyMap : [ ]
`
2022-10-28 03:16:46 +00:00
const expectedPropertiesUnwrapped = ` # block comments come through
# comments on values appear
2022-06-25 02:22:03 +00:00
person . name = Mike Wazowski
2022-02-01 04:34:17 +00:00
# comments on array values appear
person . pets .0 = cat
2024-02-20 00:39:56 +00:00
person . pets .1 . nested .0 = list entry
2022-02-01 04:34:17 +00:00
person . food .0 = pizza
`
2024-02-20 00:39:56 +00:00
const expectedPropertiesUnwrappedArrayBrackets = ` # block comments come through
# comments on values appear
person . name = Mike Wazowski
# comments on array values appear
person . pets [ 0 ] = cat
person . pets [ 1 ] . nested [ 0 ] = list entry
person . food [ 0 ] = pizza
`
2024-02-20 02:45:29 +00:00
const expectedPropertiesUnwrappedCustomSeparator = ` # block comments come through
# comments on values appear
person . name : @ Mike Wazowski
# comments on array values appear
person . pets .0 : @ cat
person . pets .1 . nested .0 : @ list entry
person . food .0 : @ pizza
`
2022-10-28 03:16:46 +00:00
const expectedPropertiesWrapped = ` # block comments come through
# comments on values appear
2022-06-25 02:22:03 +00:00
person . name = "Mike Wazowski"
# comments on array values appear
person . pets .0 = cat
2024-02-20 00:39:56 +00:00
person . pets .1 . nested .0 = "list entry"
2022-06-25 02:22:03 +00:00
person . food .0 = pizza
`
2022-10-28 03:16:46 +00:00
const expectedUpdatedProperties = ` # block comments come through
# comments on values appear
2022-06-25 02:22:03 +00:00
person . name = Mike Wazowski
2022-02-10 01:02:53 +00:00
# comments on array values appear
person . pets .0 = dog
2024-02-20 00:39:56 +00:00
person . pets .1 . nested .0 = list entry
2022-02-10 01:02:53 +00:00
person . food .0 = pizza
`
2022-06-25 02:22:03 +00:00
const expectedDecodedYaml = ` person :
2022-10-28 03:16:46 +00:00
# block comments come through
# comments on values appear
name : Mike Wazowski
2022-02-10 01:02:53 +00:00
pets :
2022-10-28 03:16:46 +00:00
# comments on array values appear
- cat
2024-02-20 00:39:56 +00:00
- nested :
- list entry
2022-02-10 01:02:53 +00:00
food :
- pizza
`
2023-10-18 01:11:53 +00:00
const expectedDecodedPersonYaml = ` # block comments come through
# comments on values appear
name : Mike Wazowski
pets :
# comments on array values appear
- cat
2024-02-20 00:39:56 +00:00
- nested :
- list entry
2023-10-18 01:11:53 +00:00
food :
- pizza
`
2022-06-25 02:22:03 +00:00
const expectedPropertiesNoComments = ` person . name = Mike Wazowski
2022-02-01 04:34:17 +00:00
person . pets .0 = cat
2024-02-20 00:39:56 +00:00
person . pets .1 . nested .0 = list entry
2022-02-01 04:34:17 +00:00
person . food .0 = pizza
`
2022-10-28 03:16:46 +00:00
const expectedPropertiesWithEmptyMapsAndArrays = ` # block comments come through
# comments on values appear
2022-06-25 02:22:03 +00:00
person . name = Mike Wazowski
2022-02-01 04:34:17 +00:00
# comments on array values appear
person . pets .0 = cat
2024-02-20 00:39:56 +00:00
person . pets .1 . nested .0 = list entry
2022-02-01 04:34:17 +00:00
person . food .0 = pizza
emptyArray =
emptyMap =
`
var propertyScenarios = [ ] formatScenario {
{
description : "Encode properties" ,
subdescription : "Note that empty arrays and maps are not encoded by default." ,
input : samplePropertiesYaml ,
2022-06-25 02:22:03 +00:00
expected : expectedPropertiesUnwrapped ,
} ,
2024-02-20 00:39:56 +00:00
{
description : "Encode properties with array brackets" ,
2024-02-20 02:45:29 +00:00
subdescription : "Declare the --properties-array-brackets flag to give array paths in brackets (e.g. SpringBoot)." ,
2024-02-20 00:39:56 +00:00
input : samplePropertiesYaml ,
expected : expectedPropertiesUnwrappedArrayBrackets ,
scenarioType : "encode-array-brackets" ,
} ,
2024-02-20 02:45:29 +00:00
{
description : "Encode properties - custom separator" ,
subdescription : "Use the --properties-customer-separator flag to specify your own key/value separator." ,
input : samplePropertiesYaml ,
expected : expectedPropertiesUnwrappedCustomSeparator ,
scenarioType : "encode-custom-separator" ,
} ,
2022-06-25 02:22:03 +00:00
{
description : "Encode properties: scalar encapsulation" ,
subdescription : "Note that string values with blank characters in them are encapsulated with double quotes" ,
input : samplePropertiesYaml ,
expected : expectedPropertiesWrapped ,
scenarioType : "encode-wrapped" ,
2022-02-01 04:34:17 +00:00
} ,
{
description : "Encode properties: no comments" ,
input : samplePropertiesYaml ,
expected : expectedPropertiesNoComments ,
expression : ` ... comments = "" ` ,
} ,
{
description : "Encode properties: include empty maps and arrays" ,
subdescription : "Use a yq expression to set the empty maps and sequences to your desired value." ,
expression : ` (.. | select( (tag == "!!map" or tag =="!!seq") and length == 0)) = "" ` ,
input : samplePropertiesYaml ,
expected : expectedPropertiesWithEmptyMapsAndArrays ,
} ,
2022-02-10 01:02:53 +00:00
{
description : "Decode properties" ,
2022-06-25 02:22:03 +00:00
input : expectedPropertiesUnwrapped ,
2022-02-10 01:02:53 +00:00
expected : expectedDecodedYaml ,
scenarioType : "decode" ,
} ,
2023-10-18 01:11:53 +00:00
{
skipDoc : true ,
description : "Decode properties - keeps key information" ,
input : expectedPropertiesUnwrapped ,
expression : ".person.name | key" ,
expected : "name\n" ,
scenarioType : "decode" ,
} ,
{
skipDoc : true ,
description : "Decode properties - keeps parent information" ,
input : expectedPropertiesUnwrapped ,
expression : ".person.name | parent" ,
expected : expectedDecodedPersonYaml ,
scenarioType : "decode" ,
} ,
{
skipDoc : true ,
description : "Decode properties - keeps path information" ,
input : expectedPropertiesUnwrapped ,
expression : ".person.name | path" ,
expected : "- person\n- name\n" ,
scenarioType : "decode" ,
} ,
2024-05-12 02:06:35 +00:00
{
description : "Decode properties: numbers" ,
subdescription : "All values are assumed to be strings when parsing properties, but you can use the `from_yaml` operator on all the strings values to autoparse into the correct type." ,
input : "a.b = 10" ,
expression : " (.. | select(tag == \"!!str\")) |= from_yaml" ,
expected : "a:\n b: 10\n" ,
scenarioType : "decode" ,
} ,
2022-11-08 02:40:00 +00:00
{
description : "Decode properties - array should be a map" ,
subdescription : "If you have a numeric map key in your property files, use array_to_map to convert them to maps." ,
input : ` things.10 = mike ` ,
expression : ` .things |= array_to_map ` ,
expected : "things:\n 10: mike\n" ,
scenarioType : "decode" ,
} ,
2022-03-01 00:29:11 +00:00
{
description : "does not expand automatically" ,
skipDoc : true ,
input : "mike = ${dontExpand} this" ,
expected : "mike: ${dontExpand} this\n" ,
scenarioType : "decode" ,
} ,
2023-03-27 02:51:08 +00:00
{
description : "print scalar" ,
skipDoc : true ,
input : "mike = cat" ,
expression : ".mike" ,
expected : "cat\n" ,
scenarioType : "roundtrip" ,
} ,
2022-02-10 01:02:53 +00:00
{
description : "Roundtrip" ,
2022-06-25 02:22:03 +00:00
input : expectedPropertiesUnwrapped ,
2022-02-10 01:02:53 +00:00
expression : ` .person.pets.0 = "dog" ` ,
expected : expectedUpdatedProperties ,
scenarioType : "roundtrip" ,
} ,
2022-10-28 03:16:46 +00:00
{
skipDoc : true ,
description : "comments on arrays roundtrip" ,
input : propertiesWithCommentInArray ,
expected : expectedPropertiesWithCommentInArrayProps ,
scenarioType : "roundtrip" ,
} ,
{
skipDoc : true ,
description : "comments on arrays decode" ,
input : propertiesWithCommentInArray ,
expected : expectedPropertiesWithCommentInArrayYaml ,
scenarioType : "decode" ,
} ,
{
skipDoc : true ,
description : "comments on map roundtrip" ,
input : propertiesWithCommentsOnMap ,
expected : expectedPropertiesWithCommentsOnMapProps ,
scenarioType : "roundtrip" ,
} ,
{
skipDoc : true ,
description : "comments on map decode" ,
input : propertiesWithCommentsOnMap ,
expected : expectedPropertiesWithCommentsOnMapYaml ,
scenarioType : "decode" ,
} ,
2022-02-10 01:02:53 +00:00
{
description : "Empty doc" ,
skipDoc : true ,
input : "" ,
expected : "" ,
scenarioType : "decode" ,
} ,
2022-02-01 04:34:17 +00:00
}
2022-06-25 02:22:03 +00:00
func documentUnwrappedEncodePropertyScenario ( w * bufio . Writer , s formatScenario ) {
2022-02-01 04:34:17 +00:00
writeOrPanic ( w , fmt . Sprintf ( "## %v\n" , s . description ) )
if s . subdescription != "" {
writeOrPanic ( w , s . subdescription )
writeOrPanic ( w , "\n\n" )
}
writeOrPanic ( w , "Given a sample.yml file of:\n" )
writeOrPanic ( w , fmt . Sprintf ( "```yaml\n%v\n```\n" , s . input ) )
writeOrPanic ( w , "then\n" )
expression := s . expression
2024-02-20 00:39:56 +00:00
prefs := NewDefaultPropertiesPreferences ( )
useArrayBracketsFlag := ""
2024-02-20 02:45:29 +00:00
useCustomSeparatorFlag := ""
2024-02-20 00:39:56 +00:00
if s . scenarioType == "encode-array-brackets" {
useArrayBracketsFlag = " --properties-array-brackets"
prefs . UseArrayBrackets = true
2024-02-20 02:45:29 +00:00
} else if s . scenarioType == "encode-custom-separator" {
prefs . KeyValueSeparator = " :@ "
useCustomSeparatorFlag = ` --properties-customer-separator=" :@ " `
2024-02-20 00:39:56 +00:00
}
2022-02-01 04:34:17 +00:00
2022-02-10 01:02:53 +00:00
if expression != "" {
2024-02-20 02:45:29 +00:00
writeOrPanic ( w , fmt . Sprintf ( "```bash\nyq -o=props%v%v '%v' sample.yml\n```\n" , useArrayBracketsFlag , useCustomSeparatorFlag , expression ) )
2022-02-01 04:34:17 +00:00
} else {
2024-02-20 02:45:29 +00:00
writeOrPanic ( w , fmt . Sprintf ( "```bash\nyq -o=props%v%v sample.yml\n```\n" , useArrayBracketsFlag , useCustomSeparatorFlag ) )
2022-02-01 04:34:17 +00:00
}
writeOrPanic ( w , "will output\n" )
2024-02-24 04:14:21 +00:00
prefs . UnwrapScalar = true
2022-02-01 04:34:17 +00:00
2024-02-24 04:14:21 +00:00
writeOrPanic ( w , fmt . Sprintf ( "```properties\n%v```\n\n" , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( prefs ) ) ) )
2022-06-25 02:22:03 +00:00
}
func documentWrappedEncodePropertyScenario ( w * bufio . Writer , s formatScenario ) {
writeOrPanic ( w , fmt . Sprintf ( "## %v\n" , s . description ) )
if s . subdescription != "" {
writeOrPanic ( w , s . subdescription )
writeOrPanic ( w , "\n\n" )
}
writeOrPanic ( w , "Given a sample.yml file of:\n" )
writeOrPanic ( w , fmt . Sprintf ( "```yaml\n%v\n```\n" , s . input ) )
writeOrPanic ( w , "then\n" )
expression := s . expression
if expression != "" {
writeOrPanic ( w , fmt . Sprintf ( "```bash\nyq -o=props --unwrapScalar=false '%v' sample.yml\n```\n" , expression ) )
} else {
writeOrPanic ( w , "```bash\nyq -o=props --unwrapScalar=false sample.yml\n```\n" )
}
writeOrPanic ( w , "will output\n" )
2024-02-24 04:14:21 +00:00
prefs := ConfiguredPropertiesPreferences . Copy ( )
prefs . UnwrapScalar = false
writeOrPanic ( w , fmt . Sprintf ( "```properties\n%v```\n\n" , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( prefs ) ) ) )
2022-02-10 01:02:53 +00:00
}
func documentDecodePropertyScenario ( w * bufio . Writer , s formatScenario ) {
writeOrPanic ( w , fmt . Sprintf ( "## %v\n" , s . description ) )
if s . subdescription != "" {
writeOrPanic ( w , s . subdescription )
writeOrPanic ( w , "\n\n" )
}
writeOrPanic ( w , "Given a sample.properties file of:\n" )
writeOrPanic ( w , fmt . Sprintf ( "```properties\n%v\n```\n" , s . input ) )
writeOrPanic ( w , "then\n" )
expression := s . expression
if expression != "" {
writeOrPanic ( w , fmt . Sprintf ( "```bash\nyq -p=props '%v' sample.properties\n```\n" , expression ) )
} else {
writeOrPanic ( w , "```bash\nyq -p=props sample.properties\n```\n" )
}
writeOrPanic ( w , "will output\n" )
2024-02-24 04:36:16 +00:00
writeOrPanic ( w , fmt . Sprintf ( "```yaml\n%v```\n\n" , mustProcessFormatScenario ( s , NewPropertiesDecoder ( ) , NewYamlEncoder ( ConfiguredYamlPreferences ) ) ) )
2022-02-10 01:02:53 +00:00
}
func documentRoundTripPropertyScenario ( w * bufio . Writer , s formatScenario ) {
writeOrPanic ( w , fmt . Sprintf ( "## %v\n" , s . description ) )
if s . subdescription != "" {
writeOrPanic ( w , s . subdescription )
writeOrPanic ( w , "\n\n" )
}
writeOrPanic ( w , "Given a sample.properties file of:\n" )
writeOrPanic ( w , fmt . Sprintf ( "```properties\n%v\n```\n" , s . input ) )
writeOrPanic ( w , "then\n" )
expression := s . expression
if expression != "" {
writeOrPanic ( w , fmt . Sprintf ( "```bash\nyq -p=props -o=props '%v' sample.properties\n```\n" , expression ) )
} else {
writeOrPanic ( w , "```bash\nyq -p=props -o=props sample.properties\n```\n" )
}
writeOrPanic ( w , "will output\n" )
2024-02-24 04:14:21 +00:00
writeOrPanic ( w , fmt . Sprintf ( "```properties\n%v```\n\n" , mustProcessFormatScenario ( s , NewPropertiesDecoder ( ) , NewPropertiesEncoder ( ConfiguredPropertiesPreferences ) ) ) )
2022-02-10 01:02:53 +00:00
}
2024-01-11 02:17:34 +00:00
func documentPropertyScenario ( _ * testing . T , w * bufio . Writer , i interface { } ) {
2022-02-10 01:02:53 +00:00
s := i . ( formatScenario )
2022-03-01 00:29:11 +00:00
if s . skipDoc {
return
}
2022-06-25 02:22:03 +00:00
switch s . scenarioType {
2024-02-20 02:45:29 +00:00
case "" , "encode-array-brackets" , "encode-custom-separator" :
2022-06-25 02:22:03 +00:00
documentUnwrappedEncodePropertyScenario ( w , s )
case "decode" :
2022-02-10 01:02:53 +00:00
documentDecodePropertyScenario ( w , s )
2022-06-25 02:22:03 +00:00
case "encode-wrapped" :
documentWrappedEncodePropertyScenario ( w , s )
case "roundtrip" :
2022-02-10 01:02:53 +00:00
documentRoundTripPropertyScenario ( w , s )
2022-06-25 02:22:03 +00:00
default :
panic ( fmt . Sprintf ( "unhandled scenario type %q" , s . scenarioType ) )
}
2022-02-01 04:34:17 +00:00
}
func TestPropertyScenarios ( t * testing . T ) {
for _ , s := range propertyScenarios {
2022-06-25 02:22:03 +00:00
switch s . scenarioType {
case "" :
2024-02-24 04:14:21 +00:00
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( ConfiguredPropertiesPreferences ) ) , s . description )
2022-06-25 02:22:03 +00:00
case "decode" :
2024-02-24 04:36:16 +00:00
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewPropertiesDecoder ( ) , NewYamlEncoder ( ConfiguredYamlPreferences ) ) , s . description )
2022-06-25 02:22:03 +00:00
case "encode-wrapped" :
2024-02-24 04:14:21 +00:00
prefs := ConfiguredPropertiesPreferences . Copy ( )
prefs . UnwrapScalar = false
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( prefs ) ) , s . description )
2024-02-20 00:39:56 +00:00
case "encode-array-brackets" :
2024-02-24 04:14:21 +00:00
prefs := ConfiguredPropertiesPreferences . Copy ( )
prefs . KeyValueSeparator = " = "
prefs . UseArrayBrackets = true
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( prefs ) ) , s . description )
2024-02-20 02:45:29 +00:00
case "encode-custom-separator" :
2024-02-24 04:14:21 +00:00
prefs := ConfiguredPropertiesPreferences . Copy ( )
prefs . KeyValueSeparator = " :@ "
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewYamlDecoder ( ConfiguredYamlPreferences ) , NewPropertiesEncoder ( prefs ) ) , s . description )
2022-06-25 02:22:03 +00:00
case "roundtrip" :
2024-02-24 04:14:21 +00:00
test . AssertResultWithContext ( t , s . expected , mustProcessFormatScenario ( s , NewPropertiesDecoder ( ) , NewPropertiesEncoder ( ConfiguredPropertiesPreferences ) ) , s . description )
2022-06-25 02:22:03 +00:00
default :
panic ( fmt . Sprintf ( "unhandled scenario type %q" , s . scenarioType ) )
2022-02-10 01:02:53 +00:00
}
2022-02-01 04:34:17 +00:00
}
genericScenarios := make ( [ ] interface { } , len ( propertyScenarios ) )
for i , s := range propertyScenarios {
genericScenarios [ i ] = s
}
documentScenarios ( t , "usage" , "properties" , genericScenarios , documentPropertyScenario )
}