# coding: utf-8 """ comment testing is all about roundtrips these can be done in the "old" way by creating a file.data and file.roundtrip but there is little flexibility in doing that but some things are not easily tested, eog. how a roundtrip changes """ import pytest from .roundtrip import dedent, round_trip, round_trip_dump, round_trip_load class TestComments: def test_no_end_of_file_eol(self): """not excluding comments caused some problems if at the end of the file without a newline. First error, then included \0""" x = """\ - europe: 10 # abc""" round_trip(x, extra='\n') with pytest.raises(AssertionError): round_trip(x, extra='a\n') def test_no_comments(self): round_trip( """ - europe: 10 - usa: - ohio: 2 - california: 9 """ ) def test_round_trip_ordering(self): round_trip( """ a: 1 b: 2 c: 3 b1: 2 b2: 2 d: 4 e: 5 f: 6 """ ) def test_complex(self): round_trip( """ - europe: 10 # top - usa: - ohio: 2 - california: 9 # o """ ) def test_dropped(self): s = """\ # comment scalar ... """ round_trip(s, 'scalar\n...\n') def test_main_mapping_begin_end(self): round_trip( """ # C start a # C start b abc: 1 ghi: 2 klm: 3 # C end a # C end b """ ) def test_reindent(self): x = """\ a: b: # comment 1 c: 1 # comment 2 """ d = round_trip_load(x) y = round_trip_dump(d, indent=4) assert y == dedent( """\ a: b: # comment 1 c: 1 # comment 2 """ ) def test_main_mapping_begin_end_items_post(self): round_trip( """ # C start a # C start b abc: 1 # abc comment ghi: 2 klm: 3 # klm comment # C end a # C end b """ ) def test_main_sequence_begin_end(self): round_trip( """ # C start a # C start b - abc - ghi - klm # C end a # C end b """ ) def test_main_sequence_begin_end_items_post(self): round_trip( """ # C start a # C start b - abc # abc comment - ghi - klm # klm comment # C end a # C end b """ ) def test_main_mapping_begin_end_complex(self): round_trip( """ # C start a # C start b abc: 1 ghi: 2 klm: 3a: alpha 3b: beta # it is all greek to me # C end a # C end b """ ) def test_09(self): # 2.9 from the examples in the spec s = """\ hr: # 1998 hr ranking - Mark McGwire - Sammy Sosa rbi: # 1998 rbi ranking - Sammy Sosa - Ken Griffey """ round_trip(s, indent=4, block_seq_indent=2) def test_09a(self): round_trip( """ hr: # 1998 hr ranking - Mark McGwire - Sammy Sosa rbi: # 1998 rbi ranking - Sammy Sosa - Ken Griffey """ ) def test_simple_map_middle_comment(self): round_trip( """ abc: 1 # C 3a # C 3b ghi: 2 """ ) def test_map_in_map_0(self): round_trip( """ map1: # comment 1 # comment 2 map2: key1: val1 """ ) def test_map_in_map_1(self): # comment is moved from value to key round_trip( """ map1: # comment 1 map2: key1: val1 """ ) def test_application_arguments(self): # application configur round_trip( """ args: username: anthon passwd: secret fullname: Anthon van der Neut tmux: session-name: test loop: wait: 10 """ ) def test_substitute(self): x = """ args: username: anthon # name passwd: secret # password fullname: Anthon van der Neut tmux: session-name: test loop: wait: 10 """ data = round_trip_load(x) data['args']['passwd'] = 'deleted password' # note the requirement to add spaces for alignment of comment x = x.replace(': secret ', ': deleted password') assert round_trip_dump(data) == dedent(x) def test_set_comment(self): round_trip( """ !!set # the beginning ? a # next one is B (lowercase) ? b # You see? Promised you. ? c # this is the end """ ) def test_omap_comment_roundtrip(self): round_trip( """ !!omap - a: 1 - b: 2 # two - c: 3 # three - d: 4 """ ) def test_omap_comment_roundtrip_pre_comment(self): round_trip( """ !!omap - a: 1 - b: 2 # two - c: 3 # three # last one - d: 4 """ ) def test_non_ascii(self): round_trip( """ verbosity: 1 # 0 is minimal output, -1 none base_url: http://gopher.net special_indices: [1, 5, 8] also_special: - a - 19 - 32 asia and europe: &asia_europe Turkey: Ankara Russia: Moscow countries: Asia: <<: *asia_europe Japan: Tokyo # 東京 Europe: <<: *asia_europe Spain: Madrid Italy: Rome """ ) def test_dump_utf8(self): import ruyaml # NOQA x = dedent( """\ ab: - x # comment - y # more comment """ ) data = round_trip_load(x) for utf in [True, False]: y = round_trip_dump(data, default_flow_style=False, allow_unicode=utf) assert y == x def test_dump_unicode_utf8(self): import ruyaml # NOQA x = dedent( """\ ab: - x # comment - y # more comment """ ) data = round_trip_load(x) for utf in [True, False]: y = round_trip_dump(data, default_flow_style=False, allow_unicode=utf) assert y == x def test_mlget_00(self): x = """\ a: - b: c: 42 - d: f: 196 e: g: 3.14 """ d = round_trip_load(x) assert d.mlget(['a', 1, 'd', 'f'], list_ok=True) == 196 # with pytest.raises(AssertionError): # d.mlget(['a', 1, 'd', 'f']) == 196 class TestInsertPopList: """list insertion is more complex than dict insertion, as you need to move the values to subsequent keys on insert""" @property def ins(self): return """\ ab: - a # a - b # b - c - d # d de: - 1 - 2 """ def test_insert_0(self): d = round_trip_load(self.ins) d['ab'].insert(0, 'xyz') y = round_trip_dump(d, indent=2) assert y == dedent( """\ ab: - xyz - a # a - b # b - c - d # d de: - 1 - 2 """ ) def test_insert_1(self): d = round_trip_load(self.ins) d['ab'].insert(4, 'xyz') y = round_trip_dump(d, indent=2) assert y == dedent( """\ ab: - a # a - b # b - c - d # d - xyz de: - 1 - 2 """ ) def test_insert_2(self): d = round_trip_load(self.ins) d['ab'].insert(1, 'xyz') y = round_trip_dump(d, indent=2) assert y == dedent( """\ ab: - a # a - xyz - b # b - c - d # d de: - 1 - 2 """ ) def test_pop_0(self): d = round_trip_load(self.ins) d['ab'].pop(0) y = round_trip_dump(d, indent=2) print(y) assert y == dedent( """\ ab: - b # b - c - d # d de: - 1 - 2 """ ) def test_pop_1(self): d = round_trip_load(self.ins) d['ab'].pop(1) y = round_trip_dump(d, indent=2) print(y) assert y == dedent( """\ ab: - a # a - c - d # d de: - 1 - 2 """ ) def test_pop_2(self): d = round_trip_load(self.ins) d['ab'].pop(2) y = round_trip_dump(d, indent=2) print(y) assert y == dedent( """\ ab: - a # a - b # b - d # d de: - 1 - 2 """ ) def test_pop_3(self): d = round_trip_load(self.ins) d['ab'].pop(3) y = round_trip_dump(d, indent=2) print(y) assert y == dedent( """\ ab: - a # a - b # b - c de: - 1 - 2 """ ) # inspired by demux' question on stackoverflow # http://stackoverflow.com/a/36970608/1307905 class TestInsertInMapping: @property def ins(self): return """\ first_name: Art occupation: Architect # This is an occupation comment about: Art Vandelay is a fictional character that George invents... """ def test_insert_at_pos_1(self): d = round_trip_load(self.ins) d.insert(1, 'last name', 'Vandelay', comment='new key') y = round_trip_dump(d) print(y) assert y == dedent( """\ first_name: Art last name: Vandelay # new key occupation: Architect # This is an occupation comment about: Art Vandelay is a fictional character that George invents... """ ) def test_insert_at_pos_0(self): d = round_trip_load(self.ins) d.insert(0, 'last name', 'Vandelay', comment='new key') y = round_trip_dump(d) print(y) assert y == dedent( """\ last name: Vandelay # new key first_name: Art occupation: Architect # This is an occupation comment about: Art Vandelay is a fictional character that George invents... """ ) def test_insert_at_pos_3(self): # much more simple if done with appending. d = round_trip_load(self.ins) d.insert(3, 'last name', 'Vandelay', comment='new key') y = round_trip_dump(d) print(y) assert y == dedent( """\ first_name: Art occupation: Architect # This is an occupation comment about: Art Vandelay is a fictional character that George invents... last name: Vandelay # new key """ ) class TestCommentedMapMerge: def test_in_operator(self): data = round_trip_load( """ x: &base a: 1 b: 2 c: 3 y: <<: *base k: 4 l: 5 """ ) assert data['x']['a'] == 1 assert 'a' in data['x'] assert data['y']['a'] == 1 assert 'a' in data['y'] def test_issue_60(self): data = round_trip_load( """ x: &base a: 1 y: <<: *base """ ) assert data['x']['a'] == 1 assert data['y']['a'] == 1 assert str(data['y']) == """ordereddict([('a', 1)])""" def test_issue_60_1(self): data = round_trip_load( """ x: &base a: 1 y: <<: *base b: 2 """ ) assert data['x']['a'] == 1 assert data['y']['a'] == 1 assert str(data['y']) == """ordereddict([('b', 2), ('a', 1)])""" class TestEmptyLines: # prompted by issue 46 from Alex Harvey def test_issue_46(self): yaml_str = dedent( """\ --- # Please add key/value pairs in alphabetical order aws_s3_bucket: 'mys3bucket' jenkins_ad_credentials: bind_name: 'CN=svc-AAA-BBB-T,OU=Example,DC=COM,DC=EXAMPLE,DC=Local' bind_pass: 'xxxxyyyy{' """ ) d = round_trip_load(yaml_str, preserve_quotes=True) y = round_trip_dump(d, explicit_start=True) assert yaml_str == y def test_multispace_map(self): round_trip( """ a: 1x b: 2x c: 3x d: 4x """ ) @pytest.mark.xfail(strict=True) def test_multispace_map_initial(self): round_trip( """ a: 1x b: 2x c: 3x d: 4x """ ) def test_embedded_map(self): round_trip( """ - a: 1y b: 2y c: 3y """ ) def test_toplevel_seq(self): round_trip( """\ - 1 - 2 - 3 """ ) def test_embedded_seq(self): round_trip( """ a: b: - 1 - 2 - 3 """ ) def test_line_with_only_spaces(self): # issue 54 yaml_str = "---\n\na: 'x'\n \nb: y\n" d = round_trip_load(yaml_str, preserve_quotes=True) y = round_trip_dump(d, explicit_start=True) stripped = "" for line in yaml_str.splitlines(): stripped += line.rstrip() + '\n' print(line + '$') assert stripped == y def test_some_eol_spaces(self): # spaces after tokens and on empty lines yaml_str = '--- \n \na: "x" \n \nb: y \n' d = round_trip_load(yaml_str, preserve_quotes=True) y = round_trip_dump(d, explicit_start=True) stripped = "" for line in yaml_str.splitlines(): stripped += line.rstrip() + '\n' print(line + '$') assert stripped == y def test_issue_54_not_ok(self): yaml_str = dedent( """\ toplevel: # some comment sublevel: 300 """ ) d = round_trip_load(yaml_str) print(d.ca) y = round_trip_dump(d, indent=4) print(y.replace('\n', '$\n')) assert yaml_str == y def test_issue_54_ok(self): yaml_str = dedent( """\ toplevel: # some comment sublevel: 300 """ ) d = round_trip_load(yaml_str) y = round_trip_dump(d, indent=4) assert yaml_str == y def test_issue_93(self): round_trip( """\ a: b: - c1: cat # a1 # my comment on catfish - c2: catfish # a2 """ ) def test_issue_93_00(self): round_trip( """\ a: - - c1: cat # a1 # my comment on catfish - c2: catfish # a2 """ ) def test_issue_93_01(self): round_trip( """\ - - c1: cat # a1 # my comment on catfish - c2: catfish # a2 """ ) def test_issue_93_02(self): # never failed as there is no indent round_trip( """\ - c1: cat # my comment on catfish - c2: catfish """ ) def test_issue_96(self): # inserted extra line on trailing spaces round_trip( """\ a: b: c: c_val d: e: g: g_val """ ) class TestUnicodeComments: def test_issue_55(self): # reported by Haraguroicha Hsu round_trip( """\ name: TEST description: test using author: Harguroicha sql: command: |- select name from testtbl where no = :no ci-test: - :no: 04043709 # 小花 - :no: 05161690 # 茶 - :no: 05293147 # 〇𤋥川 - :no: 05338777 # 〇〇啓 - :no: 05273867 # 〇 - :no: 05205786 # 〇𤦌 """ ) class TestEmptyValueBeforeComments: def test_issue_25a(self): round_trip( """\ - a: b c: d d: # foo - e: f """ ) def test_issue_25a1(self): round_trip( """\ - a: b c: d d: # foo e: f """ ) def test_issue_25b(self): round_trip( """\ var1: #empty var2: something #notempty """ ) def test_issue_25c(self): round_trip( """\ params: a: 1 # comment a b: # comment b c: 3 # comment c """ ) def test_issue_25c1(self): round_trip( """\ params: a: 1 # comment a b: # comment b # extra c: 3 # comment c """ ) def test_issue_25_00(self): round_trip( """\ params: a: 1 # comment a b: # comment b """ ) def test_issue_25_01(self): round_trip( """\ a: # comment 1 # comment 2 - b: # comment 3 c: 1 # comment 4 """ ) def test_issue_25_02(self): round_trip( """\ a: # comment 1 # comment 2 - b: 2 # comment 3 """ ) def test_issue_25_03(self): s = """\ a: # comment 1 # comment 2 - b: 2 # comment 3 """ round_trip(s, indent=4, block_seq_indent=2) def test_issue_25_04(self): round_trip( """\ a: # comment 1 # comment 2 b: 1 # comment 3 """ ) def test_flow_seq_within_seq(self): round_trip( """\ # comment 1 - a - b # comment 2 - c - d # comment 3 - [e] - f # comment 4 - [] """ ) def test_comment_after_block_scalar_indicator(self): round_trip( """\ a: | # abc test 1 test 2 # all done """ ) test_block_scalar_commented_line_template = """\ y: p # Some comment a: | x {}b: y """ class TestBlockScalarWithComments: # issue 99 reported by Colm O'Connor def test_scalar_with_comments(self): import ruyaml # NOQA for x in [ "", '\n', '\n# Another comment\n', '\n\n', '\n\n# abc\n#xyz\n', '\n\n# abc\n#xyz\n', '# abc\n\n#xyz\n', '\n\n # abc\n #xyz\n', ]: commented_line = test_block_scalar_commented_line_template.format(x) data = round_trip_load(commented_line) assert round_trip_dump(data) == commented_line