From bb97fb5f30c41e82b86eb88eecf44a49b2bd9780 Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Wed, 15 Oct 2014 17:05:02 +0200 Subject: Add Screenplay class This is to be able to access title page data. --- tests/fountain_test.py | 104 ++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) (limited to 'tests') diff --git a/tests/fountain_test.py b/tests/fountain_test.py index e265da9..9a5d308 100644 --- a/tests/fountain_test.py +++ b/tests/fountain_test.py @@ -14,25 +14,25 @@ from StringIO import StringIO def parse(lines): content = '\n'.join(lines) - return fountain.parse(StringIO(content)) + return list(fountain.parse(StringIO(content))) class SlugTests(TestCase): def test_slug_with_prefix(self): - paras = list(parse([ + paras = parse([ 'INT. SOMEWHERE - DAY', '', 'THIS IS JUST ACTION', - ])) + ]) self.assertEquals([Slug, Action], [type(p) for p in paras]) def test_slug_must_be_single_line(self): - paras = list(parse([ + paras = parse([ 'INT. SOMEWHERE - DAY', 'ANOTHER LINE', '', 'Some action', - ])) + ]) self.assertEquals([Dialog, Action], [type(p) for p in paras]) # What looks like a scene headingis parsed as a character name. # Unexpected perhaps, but that's how I interpreted the spec. @@ -40,10 +40,10 @@ class SlugTests(TestCase): self.assertEquals([plain('Some action')], paras[1].lines) def test_action_is_not_a_slug(self): - paras = list(parse([ + paras = parse([ '', 'THIS IS JUST ACTION', - ])) + ]) self.assertEquals([Action], [type(p) for p in paras]) def test_two_lines_creates_no_slug(self): @@ -151,25 +151,25 @@ class DialogTests(TestCase): # Fountain would not be able to support a character named "23". We # might need a syntax to force a character element. def test_nonalpha_character(self): - paras = list(parse([ + paras = parse([ '23', 'Hello', - ])) + ]) self.assertEquals([Action], [type(p) for p in paras]) def test_twospaced_line_is_not_character(self): - paras = list(parse([ + paras = parse([ 'SCANNING THE AISLES... ', 'Where is that pit boss?', - ])) + ]) self.assertEquals([Action], [type(p) for p in paras]) def test_simple_parenthetical(self): - paras = list(parse([ + paras = parse([ 'STEEL', '(starting the engine)', 'So much for retirement!', - ])) + ]) self.assertEquals(1, len(paras)) dialog = paras[0] self.assertEqual(2, len(dialog.blocks)) @@ -183,12 +183,12 @@ class DialogTests(TestCase): ) def test_twospace_keeps_dialog_together(self): - paras = list(parse([ + paras = parse([ 'SOMEONE', 'One', ' ', 'Two', - ])) + ]) self.assertEquals([Dialog], [type(p) for p in paras]) self.assertEquals([ (False, plain('One')), @@ -197,13 +197,13 @@ class DialogTests(TestCase): ], paras[0].blocks) def test_dual_dialog(self): - paras = list(parse([ + paras = parse([ 'BRICK', 'Fuck retirement.', '', 'STEEL ^', 'Fuck retirement!', - ])) + ]) self.assertEquals([DualDialog], [type(p) for p in paras]) dual = paras[0] self.assertEquals(plain('BRICK'), dual.left.character) @@ -218,12 +218,12 @@ class DialogTests(TestCase): ) def test_dual_dialog_without_previous_dialog_is_ignored(self): - paras = list(parse([ + paras = parse([ 'Brick strolls down the street.', '', 'BRICK ^', 'Nice retirement.', - ])) + ]) self.assertEquals([Action, Dialog], [type(p) for p in paras]) dialog = paras[1] self.assertEqual(plain('BRICK ^'), dialog.character) @@ -232,13 +232,13 @@ class DialogTests(TestCase): ], dialog.blocks) def test_leading_and_trailing_spaces_in_dialog(self): - paras = list(parse([ + paras = parse([ 'JULIET', 'O Romeo, Romeo! wherefore art thou Romeo?', ' Deny thy father and refuse thy name; ', 'Or, if thou wilt not, be but sworn my love,', " And I'll no longer be a Capulet.", - ])) + ]) self.assertEquals([Dialog], [type(p) for p in paras]) self.assertEquals([ (False, plain(u'O Romeo, Romeo! wherefore art thou Romeo?')), @@ -251,84 +251,84 @@ class DialogTests(TestCase): class TransitionTests(TestCase): def test_standard_transition(self): - paras = list(parse([ + paras = parse([ 'Jack begins to argue vociferously in Vietnamese (?)', '', 'CUT TO:', '', "EXT. BRICK'S POOL - DAY", - ])) + ]) self.assertEquals([Action, Transition, Slug], [type(p) for p in paras]) def test_transition_must_end_with_to(self): - paras = list(parse([ + paras = parse([ 'CUT TOO:', '', "EXT. BRICK'S POOL - DAY", - ])) + ]) self.assertEquals([Action, Slug], [type(p) for p in paras]) def test_transition_needs_to_be_upper_case(self): - paras = list(parse([ + paras = parse([ 'Jack begins to argue vociferously in Vietnamese (?)', '', 'cut to:', '', "EXT. BRICK'S POOL - DAY", - ])) + ]) self.assertEquals([Action, Action, Slug], [type(p) for p in paras]) def test_not_a_transition_on_trailing_whitespace(self): - paras = list(parse([ + paras = parse([ 'Jack begins to argue vociferously in Vietnamese (?)', '', 'CUT TO: ', '', "EXT. BRICK'S POOL - DAY", - ])) + ]) self.assertEquals([Action, Action, Slug], [type(p) for p in paras]) def test_transition_does_not_have_to_be_followed_by_slug(self): # The "followed by slug" requirement is gone from the Jan 2012 spec - paras = list(parse([ + paras = parse([ 'Bill lights a cigarette.', '', 'CUT TO:', '', 'SOME GUY mowing the lawn.', - ])) + ]) self.assertEquals( [Action, Transition, Action], [type(p) for p in paras] ) def test_greater_than_sign_means_transition(self): - paras = list(parse([ + paras = parse([ 'Bill blows out the match.', '', '> FADE OUT.', '', '.DARKNESS', - ])) + ]) self.assertEquals([Action, Transition, Slug], [type(p) for p in paras]) self.assertEquals(plain('FADE OUT.'), paras[1].line) def test_centered_text_is_not_parsed_as_transition(self): - paras = list(parse([ + paras = parse([ 'Bill blows out the match.', '', '> THE END. <', '', 'bye!' - ])) + ]) self.assertEquals([Action, Action, Action], [type(p) for p in paras]) def test_transition_at_end(self): - paras = list(parse([ + paras = parse([ 'They stroll hand in hand down the street.', '', '> FADE OUT.', - ])) + ]) self.assertEquals([Action, Transition], [type(p) for p in paras]) self.assertEquals(plain('FADE OUT.'), paras[1].line) @@ -336,12 +336,12 @@ class TransitionTests(TestCase): class ActionTests(TestCase): def test_action_preserves_leading_whitespace(self): - paras = list(parse([ + paras = parse([ 'hello', '', ' two spaces', ' three spaces ', - ])) + ]) self.assertEquals([Action, Action], [type(p) for p in paras]) self.assertEquals( [ @@ -351,7 +351,7 @@ class ActionTests(TestCase): ) def test_single_centered_line(self): - paras = list(parse(['> center me! <'])) + paras = parse(['> center me! <']) self.assertEquals([Action], [type(p) for p in paras]) self.assertTrue(paras[0].centered) @@ -361,7 +361,7 @@ class ActionTests(TestCase): ' > second! <', '> third!< ', ] - paras = list(parse(lines)) + paras = parse(lines) self.assertEquals([Action], [type(p) for p in paras]) self.assertTrue(paras[0].centered) self.assertEquals([ @@ -371,11 +371,11 @@ class ActionTests(TestCase): ], paras[0].lines) def test_upper_case_centered_not_parsed_as_dialog(self): - paras = list(parse([ + paras = parse([ '> FIRST! <', ' > SECOND! <', '> THIRD! <', - ])) + ]) self.assertEquals([Action], [type(p) for p in paras]) self.assertTrue(paras[0].centered) @@ -385,7 +385,7 @@ class ActionTests(TestCase): '> second! <', 'third!', ] - paras = list(parse(lines)) + paras = parse(lines) self.assertEquals([Action], [type(p) for p in paras]) self.assertFalse(paras[0].centered) self.assertEquals([plain(line) for line in lines], paras[0].lines) @@ -393,12 +393,12 @@ class ActionTests(TestCase): class SynopsisTests(TestCase): def test_synopsis_after_slug_adds_synopsis_to_scene(self): - paras = list(parse([ + paras = parse([ "EXT. BRICK'S PATIO - DAY", '', "= Set up Brick & Steel's new life." '', - ])) + ]) self.assertEquals([Slug], [type(p) for p in paras]) self.assertEquals( "Set up Brick & Steel's new life.", @@ -406,11 +406,11 @@ class SynopsisTests(TestCase): ) def test_synopsis_in_section(self): - paras = list(parse([ + paras = parse([ '# section one', '', '= In which we get to know our characters' - ])) + ]) self.assertEquals([Section], [type(p) for p in paras]) self.assertEquals( 'In which we get to know our characters', @@ -418,11 +418,11 @@ class SynopsisTests(TestCase): ) def test_synopsis_syntax_parsed_as_literal(self): - paras = list(parse([ + paras = parse([ 'Some action', '', '= A line that just happens to look like a synopsis' - ])) + ]) self.assertEquals([Action, Action], [type(p) for p in paras]) self.assertEquals( [plain('= A line that just happens to look like a synopsis')], @@ -485,9 +485,9 @@ class TitlePageTests(TestCase): class PageBreakTests(TestCase): def test_page_break_is_parsed(self): - paras = list(parse([ + paras = parse([ '====', '', 'So here we go' - ])) + ]) self.assertEquals([PageBreak, Action], [type(p) for p in paras]) -- cgit From 8b154c0d5b9268d5e41a7774d6e87bbbac1a33e4 Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Thu, 23 Jul 2015 09:33:21 +0200 Subject: Add test for dual dialogue in FDX output --- tests/files/dual-dialogue.fountain.fdx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/files/dual-dialogue.fountain.fdx (limited to 'tests') diff --git a/tests/files/dual-dialogue.fountain.fdx b/tests/files/dual-dialogue.fountain.fdx new file mode 100644 index 0000000..16d022e --- /dev/null +++ b/tests/files/dual-dialogue.fountain.fdx @@ -0,0 +1,21 @@ + + + + + + + GIRL + + + Hey! + + + GUY + + + Hello! + + + + + -- cgit From fd832267cf7b55b4d3cdc56e313eb2bec215cc55 Mon Sep 17 00:00:00 2001 From: michaelx386 Date: Fri, 18 Sep 2015 17:51:49 +0100 Subject: Parse files with BOM present; fixes #5 --- tests/files/utf-8-bom.fountain | 18 ++++++++++++++++ tests/files/utf-8-bom.fountain.fdx | 43 +++++++++++++++++++++++++++++++++++++ tests/files/utf-8-bom.fountain.html | 6 ++++++ 3 files changed, 67 insertions(+) create mode 100644 tests/files/utf-8-bom.fountain create mode 100644 tests/files/utf-8-bom.fountain.fdx create mode 100644 tests/files/utf-8-bom.fountain.html (limited to 'tests') diff --git a/tests/files/utf-8-bom.fountain b/tests/files/utf-8-bom.fountain new file mode 100644 index 0000000..ddfe1f9 --- /dev/null +++ b/tests/files/utf-8-bom.fountain @@ -0,0 +1,18 @@ +EXT. SOMEWHERE - DAY + +GUY and GURL walk down the street. + +It's a sunny day. +Sunnier than normal. +Too sunny to be funny. + +GUY +So what's up? + +GURL +Nothing much. +Just thinking. +And you? + +GUY +Nothing. \ No newline at end of file diff --git a/tests/files/utf-8-bom.fountain.fdx b/tests/files/utf-8-bom.fountain.fdx new file mode 100644 index 0000000..9701f3a --- /dev/null +++ b/tests/files/utf-8-bom.fountain.fdx @@ -0,0 +1,43 @@ + + + + + + EXT. SOMEWHERE - DAY + + + GUY and GURL walk down the street. + + + It's a sunny day. + + Sunnier than normal. + + Too sunny to be funny. + + + GUY + + + So what's up? + + + GURL + + + Nothing much. + + + Just thinking. + + + And you? + + + GUY + + + Nothing. + + + diff --git a/tests/files/utf-8-bom.fountain.html b/tests/files/utf-8-bom.fountain.html new file mode 100644 index 0000000..70043dd --- /dev/null +++ b/tests/files/utf-8-bom.fountain.html @@ -0,0 +1,6 @@ +
EXT. SOMEWHERE - DAY
+

GUY and GURL walk down the street.

+

It's a sunny day.
Sunnier than normal.
Too sunny to be funny.

+

GUY

So what's up?

+

GURL

Nothing much.

Just thinking.

And you?

+

GUY

Nothing.

-- cgit From d4a721b470a960e71a683b8ebff61b26c868d1cd Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Tue, 17 Nov 2015 08:49:32 +0100 Subject: Support non-alphanumeric character names with "@" Fixes #22 --- tests/fountain_test.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/fountain_test.py b/tests/fountain_test.py index 9a5d308..95a4a81 100644 --- a/tests/fountain_test.py +++ b/tests/fountain_test.py @@ -148,8 +148,10 @@ class DialogTests(TestCase): self.assertEquals(Dialog, type(dialog)) self.assertEquals(plain('SOME GUY'), dialog.character) - # Fountain would not be able to support a character named "23". We - # might need a syntax to force a character element. + + # Spec http://fountain.io/syntax#section-character: + # Character names must include at least one alphabetical character. + # "R2D2" works, but "23" does not. def test_nonalpha_character(self): paras = parse([ '23', @@ -157,6 +159,16 @@ class DialogTests(TestCase): ]) self.assertEquals([Action], [type(p) for p in paras]) + # Spec http://fountain.io/syntax#section-character: + # You can force a Character element by preceding it with the "at" symbol @. + def test_at_sign_forces_dialog(self): + paras = parse([ + '@McCLANE', + 'Yippee ki-yay', + ]) + self.assertEquals([Dialog], [type(p) for p in paras]) + self.assertEquals(plain('McCLANE'), paras[0].character) + def test_twospaced_line_is_not_character(self): paras = parse([ 'SCANNING THE AISLES... ', -- cgit From fe3a3c714221288b81127beee389b0431cad8527 Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Tue, 17 Nov 2015 08:54:16 +0100 Subject: Test that alphanumeric character names work --- tests/fountain_test.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/fountain_test.py b/tests/fountain_test.py index 95a4a81..fff1e48 100644 --- a/tests/fountain_test.py +++ b/tests/fountain_test.py @@ -148,6 +148,13 @@ class DialogTests(TestCase): self.assertEquals(Dialog, type(dialog)) self.assertEquals(plain('SOME GUY'), dialog.character) + def test_alphanumeric_character(self): + paras = parse([ + 'R2D2', + 'Bee-bop', + ]) + self.assertEquals([Dialog], [type(p) for p in paras]) + self.assertEquals(plain('R2D2'), paras[0].character) # Spec http://fountain.io/syntax#section-character: # Character names must include at least one alphabetical character. -- cgit From e76e044308a8d3b5fa93bc9a2657897c480bb782 Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Thu, 14 Apr 2016 00:10:15 +0200 Subject: Show multiple spaces in a row as is in HTML & PDF Not sure if FDX output should use   Let's keep using spaces for now. Closes #30 --- tests/files/indentation.fountain | 11 +++++++++++ tests/files/indentation.fountain.fdx | 24 ++++++++++++++++++++++++ tests/files/indentation.fountain.html | 6 ++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/files/indentation.fountain create mode 100644 tests/files/indentation.fountain.fdx create mode 100644 tests/files/indentation.fountain.html (limited to 'tests') diff --git a/tests/files/indentation.fountain b/tests/files/indentation.fountain new file mode 100644 index 0000000..1640032 --- /dev/null +++ b/tests/files/indentation.fountain @@ -0,0 +1,11 @@ +EXT. INDENTATION TEST + + Four spaces + + Three spaces + + Two spaces + + One space + +No spaces diff --git a/tests/files/indentation.fountain.fdx b/tests/files/indentation.fountain.fdx new file mode 100644 index 0000000..958417f --- /dev/null +++ b/tests/files/indentation.fountain.fdx @@ -0,0 +1,24 @@ + + + + + + EXT. INDENTATION TEST + + + Four spaces + + + Three spaces + + + Two spaces + + + One space + + + No spaces + + + diff --git a/tests/files/indentation.fountain.html b/tests/files/indentation.fountain.html new file mode 100644 index 0000000..491b515 --- /dev/null +++ b/tests/files/indentation.fountain.html @@ -0,0 +1,6 @@ +
EXT. INDENTATION TEST
+

    Four spaces

+

   Three spaces

+

  Two spaces

+

 One space

+

No spaces

-- cgit