import YamlTest
from yaml.load import *
from here import flushLeft
from test import assertEquals
from yaml.stream import NestedText, CommentEater, split

here = flushLeft # pardon the Perlism

def stringStream(str):
    return StringStream(here(str))

def commentEater(str):
    return CommentEater(stringStream(str))

def nestedText(str):
    return NestedText(stringStream(str))

def nestedDocs(str):
    return NestedDocs(stringStream(str))

class Test(YamlTest.YamlTest):
    def tryPop(self, expected):
        assertEquals(self.nt.pop(), expected)
        
    def tryPopNestedLines(self, expected):
        assertEquals(self.nt.popNestedLines(), expected)
        
    def tryPeek(self, expected):
        assertEquals(self.nt.peek(), expected)

    def test1(self):
        self.nt = nestedText(
            """
            1a
             2a
             2b
                 3a
             2c
            1b
            """)
        self.tryPop('1a')
        self.nt.nestToNextLine()
        self.tryPop('2a')
        self.tryPop('2b')
        self.nt.nestToNextLine()
        self.tryPop('3a')
        self.tryPop(None)
        self.tryPop('2c')
        self.tryPop(None)
        self.tryPeek('1b')
        self.tryPop('1b')
        self.tryPop('')
        self.tryPop(None)
        
    def test2(self):
        self.nt = nestedText("""
            apple
                banana
                   foo
            """)
        self.tryPop('apple')
        self.nt.nestToNextLine()
        self.tryPop('banana')
        self.nt.nestBySpecificAmount(2)
        self.tryPop(' foo')

    def test3(self):
        self.nt = nestedDocs("""
            seattle
            --- foo
            bluffton
            """)
        assertEquals(self.nt.popDocSep(), '---')
        self.tryPop('seattle')
        self.tryPop(None)
        assertEquals(self.nt.popDocSep(), '--- foo')
        self.tryPop('bluffton')
        self.tryPop(None)

    def testEatComments(self):
        self.nt = commentEater("""
            # ignore
              # these
            silly
            """)
        self.tryPop('silly')

    def testNestedDocsEatComments(self):
        self.nt = nestedDocs("""
            # foo
              # bar
            ---
            shabazz
            """)
        self.nt.popDocSep()
        self.tryPop('shabazz')
        assertEquals(self.nt.lastLineRead(), 4)

    def testNestedTextEatNewline(self):
        self.nt = nestedDocs("""
            
            ---
            shabazz
            """)
        self.nt.popDocSep()
        self.tryPop('shabazz')

    def testDocSep(self):
        data = here("""
            --- city
            seattle
            --- town
            bluffton
            """)
        self.nt = NestedDocs(StringStream(data))
        assertEquals(self.nt.popDocSep(), '--- city')
        self.tryPop('seattle')
        self.tryPop(None)
        assertEquals(self.nt.popDocSep(), '--- town')
        self.tryPop('bluffton')
        self.tryPop(None)

        data = here("""
            # comments at top
            # should be ignored
            """) + data
        self.nt = NestedDocs(StringStream(data))
        assertEquals(self.nt.popDocSep(), '--- city')
        self.tryPop('seattle')

    def testNestedComments(self):
        self.nt = nestedText("""
            apple
              # ignore this comment
                banana
                   foo
            """)
        self.tryPop('apple')
        self.nt.nestToNextLine()
        self.tryPop('banana')
        self.nt.nestBySpecificAmount(2)
        self.tryPop(' foo')

    def testStream(self):
        stream = StringStream(here("""
            python
            perl
            java
            """))
        assertEquals(stream.get(), "python")
        assertEquals(stream.get(), "perl")
        assertEquals(stream.get(), "java")
        
    def test1(self):
        self.nt = nestedText(
            """
            1a
             2a
             2b
                 3a
             2c
            1b
            """)
        self.tryPop('1a')
        self.nt.nestToNextLine()
        self.tryPop('2a')
        self.tryPop('2b')
        self.nt.nestToNextLine()
        self.tryPop('3a')
        self.tryPop(None)
        self.tryPop('2c')
        self.tryPop(None)
        self.tryPeek('1b')
        self.tryPop('1b')
        self.tryPop(None)
        
    def XXXtestEmptyLines(self):
        # not sure if this is valid test any more
        self.nt = nestedDocs("""
            ---
             apple

                banana
            """)
        self.nt.popDocSep()
        self.nt.nestToNextLine()
        self.tryPop('apple')
        self.nt.nestToNextLine()
        self.tryPop('')
        self.nt.nestToNextLine()
        self.tryPop('banana')

    def testFoldedCase(self):
        self.nt = nestedText(
            """
            ---
             Aaa
             Bbb

               11
               22

             Ccc
            """)
        self.nt.pop()
        self.nt.nestToNextLine()
        self.tryPop('Aaa')
        self.tryPop('Bbb')
        self.tryPop('')

    def testRedHerringDocSep(self):
        self.nt = nestedDocs(
            """
            ---
            foo:
                ---
            """)
        self.nt.popDocSep()
        self.tryPop('foo:')
        self.nt.nestToNextLine()
        self.tryPop('---')

    def testGetToNextIndent(self):
        self.nt = nestedText(
            """
            ---
            line1: this is
               continued
            line2
            """)
        self.nt.pop()
        self.nt.nestToNextLine()
        self.tryPop('line1: this is')
        self.tryPopNestedLines(['continued'])
        self.tryPop('line2')
            
    def testGetToNextIndent(self):
        self.nt = nestedText(
            """
            ---
            key1: this is
               continued
               with multiple lines
            key2:
                 key2a:
                   hello
                   world
            key3:
            """)
        self.nt.pop()
        self.nt.nestToNextLine()
        self.tryPop('key1: this is')
        self.tryPopNestedLines(['continued', 'with multiple lines'])
        self.tryPop('key2:')
        self.nt.nestToNextLine()
        self.tryPop('key2a:')
        self.tryPopNestedLines(['hello', 'world'])
            
    def testPopNestedLinesWithNoneNested(self):
        self.nt = nestedText(
            """
            ---
            - apple
            - banana
            - carrot
            """)
        self.nt.pop()
        self.nt.nestToNextLine()
        self.tryPop('- apple')
        self.tryPopNestedLines([])
        self.tryPop('- banana')

    def testLineNumbers(self):
        data = \
            """
            one
            two
            #
            three
            """
        stream = StringStream(here(data))
        stream.get()
        assertEquals(stream.lastLineRead(), 1)
        stream.get()
        assertEquals(stream.lastLineRead(), 2)
        nt = nestedText(data)
        nt.pop()
        assertEquals(nt.lastLineRead(), 1)
        nt.pop()
        assertEquals(nt.lastLineRead(), 2)
        nt.pop()  # eats a comment too
        assertEquals(nt.lastLineRead(), 4)

    def testSplit(self):
        assertEquals(split("foo\nbar"), ['foo', 'bar'])
        assertEquals(split("foo\nbar\n"), ['foo', 'bar'])        

    def testLoaderException(self):
        import yaml
        from yaml.stream import YamlLoaderException
        exception = None
        try:
            yaml.load('invalid YAML').next()
        except YamlLoaderException, e:
            exception = e
        assertEquals(exception.lineNum, 1)
            

if __name__ == '__main__':
    import unittest
    unittest.main()
