Test-Driven Synthesis Daniel Perelman 1 Sumit Gulwani 2 Dan Grossman - - PowerPoint PPT Presentation

test driven synthesis
SMART_READER_LITE
LIVE PREVIEW

Test-Driven Synthesis Daniel Perelman 1 Sumit Gulwani 2 Dan Grossman - - PowerPoint PPT Presentation

Test-Driven Synthesis Daniel Perelman 1 Sumit Gulwani 2 Dan Grossman 1 Peter Provost 3 1 University of Washington 2 Microsoft Research 3 Microsoft Corporation June 11, 2014 TDD example 1 Test cases: Program: wrap(string s, int len) { // do


slide-1
SLIDE 1

Test-Driven Synthesis

Daniel Perelman1 Sumit Gulwani2 Dan Grossman1 Peter Provost3

1University of Washington 2Microsoft Research 3Microsoft Corporation

June 11, 2014

slide-2
SLIDE 2

TDD example1

Test cases: Program: wrap(string s, int len) { // do nothing throw new NotImplementedException(); }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

2 / 49

slide-3
SLIDE 3

TDD example1

Test cases:

  • 1. wrap("word", 5)

== "word" Program: wrap(string s, int len) { // return constant "word" return "word"; }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

3 / 49

slide-4
SLIDE 4

TDD example1

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar" Program: wrap(string s, int len) { // return input string return s; }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

4 / 49

slide-5
SLIDE 5

TDD example1

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord" Program: wrap(string s, int len) { // return input if short if(s.Len ≤ len) return s; else return "Long\nWord"; }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

5 / 49

slide-6
SLIDE 6

TDD example1

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

6 / 49

slide-7
SLIDE 7

TDD example1

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // wrap word to length len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + wrap(s[len:], len); }

1http://blog.8thlight.com/uncle-bob/2013/05/27/

TheTransformationPriorityPremise.html

7 / 49

slide-8
SLIDE 8

Google’s Real TDD2

2http://googletesting.blogspot.com/2014/04/

the-real-test-driven-development.html

8 / 49

slide-9
SLIDE 9

Google’s Real TDD2 (April Fools’ Day joke)

2http://googletesting.blogspot.com/2014/04/

the-real-test-driven-development.html

9 / 49

slide-10
SLIDE 10

Example domain: string transformations

“Spreadsheet Data Manipulation using Examples, CACM 2012, Sumit Gulwani, William Harris, Rishabh Singh” ⇓ “Spreadsheet Data Manipulation using Examples\n Gulwani, S.; Harris, W.; Singh, R.\n Communications of the ACM, 2012”

10 / 49

slide-11
SLIDE 11

Example domain: table transformations

Qual 1 Qual 2 Qual 3 Andrew 01.02.2003 27.06.2008 06.04.2007 Ben 31.08.2001 05.07.2004 Carl 18.04.2003 09.12.2009 ⇓ Andrew Qual 1 01.02.2003 Andrew Qual 2 27.06.2008 Andrew Qual 3 06.04.2007 Ben Qual 1 31.08.2001 Ben Qual 3 05.07.2004 Carl Qual 2 18.04.2003 Carl Qual 3 09.12.2009

11 / 49

slide-12
SLIDE 12

Example domain: XML transformations

<doc> <p>1</p> <p class=✬a✬>2</p> <p>3</p> <p>4</p> <p class=✬b✬>5</p> <p>6</p> <p class=✬c✬>7</p> </doc> ⇒ <doc> <p>1</p> <p class=✬a✬>2</p> <p class=✬a✬>3</p> <p class=✬a✬>4</p> <p class=✬b✬>5</p> <p class=✬b✬>6</p> <p class=✬c✬>7</p> </doc>

12 / 49

slide-13
SLIDE 13

Workflow

domain expert user DSL (library+grammar) test cases synthesize program program P done? generate new test case

  • utput program

no yes

13 / 49

slide-14
SLIDE 14

Workflow

domain expert user DSL (library+grammar) test cases synthesize program program P done? generate new test case

  • utput program

no yes

14 / 49

slide-15
SLIDE 15

Workflow

domain expert user DSL (library+grammar) test cases sequence sythesize change program P done? generate new test case

  • utput program

no yes

15 / 49

slide-16
SLIDE 16

Contrast with genetic programming

domain expert user DSL (library+grammar) fitness function f sythesize change program P f (P) ≥ α generate new test case

  • utput program

no yes

16 / 49

slide-17
SLIDE 17

Workflow

domain expert user DSL (library+grammar) test cases sequence sythesize change program P done? generate new test case

  • utput program

no yes

17 / 49

slide-18
SLIDE 18

Workflow

domain expert user DSL (library+grammar) test cases sequence sythesize change program P done? generate new test case

  • utput program

no yes

18 / 49

slide-19
SLIDE 19

Modifying program

◮ Replace single subexpression on

new test case’s path

◮ Where to modify program ◮ What to replace with

19 / 49

slide-20
SLIDE 20

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

20 / 49

slide-21
SLIDE 21

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

21 / 49

slide-22
SLIDE 22

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

22 / 49

slide-23
SLIDE 23

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

23 / 49

slide-24
SLIDE 24

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

24 / 49

slide-25
SLIDE 25

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

25 / 49

slide-26
SLIDE 26

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

26 / 49

slide-27
SLIDE 27

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

27 / 49

slide-28
SLIDE 28

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

28 / 49

slide-29
SLIDE 29

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

29 / 49

slide-30
SLIDE 30

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; }

30 / 49

slide-31
SLIDE 31

Where to modify

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord"

  • 5. wrap("LongerWord", 2)

== "Lo\nng\ner\nWo\nrd" Program: wrap(string s, int len) { // wrap word to length len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + wrap(s[len:], len); }

31 / 49

slide-32
SLIDE 32

What to put there

◮ DSL defines space of expressions ◮ Prefer expressions found in

previous program

◮ e.g., wrap(s[len:], len) contains

s[len:]

32 / 49

slide-33
SLIDE 33

Conditionals

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord" test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • 33 / 49
slide-34
SLIDE 34

Conditionals

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord" test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • 34 / 49
slide-35
SLIDE 35

Conditionals

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord" test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • guard

1 2 3 4 s == "word" T len == 6 T T s.Len == len T s.Len ≤ len T T

35 / 49

slide-36
SLIDE 36

Conditionals

Test cases:

  • 1. wrap("word", 5)

== "word"

  • 2. wrap("foobar", 6)

== "foobar"

  • 3. wrap("LongWord", 4)

== "Long\nWord"

  • 4. wrap("LongerWord", 6)

== "Longer\nWord" test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • guard

1 2 3 4 s == "word" T len == 6 T T s.Len == len T s.Len ≤ len T T

36 / 49

slide-37
SLIDE 37

Conditionals

Program: wrap(string s, int len) { // split string at len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + s[len:]; } test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • guard

1 2 3 4 s == "word" T len == 6 T T s.Len == len T s.Len ≤ len T T

37 / 49

slide-38
SLIDE 38

Loops

Program: wrap(string s, int len) { // wrap word to length len if(s.Len ≤ len) return s; else return s[0:len] + "\n" + wrap(s[len:], len); } test case program path 1 2 3 4 "" "word"

  • "foobar"
  • "Long\nWord"
  • "Longer\nWord"
  • s
  • s[0:len] +

"\n" + s[:len]

  • guard

1 2 3 4 s == "word" T len == 6 T T s.Len == len T s.Len ≤ len T T

38 / 49

slide-39
SLIDE 39

Loops

◮ Recursion (if in DSL) ◮ Higher-order functions (if in DSL) ◮ Direct support for certain loops:

see paper for details

39 / 49

slide-40
SLIDE 40

Evaluation

◮ Three DSLs focused on end-user data transformation tasks.

◮ String transformations (FlashFill+extensions) ◮ Spreadsheet table transformations ◮ XML transformations

◮ Able to synthesize many examples from help forums in under

a minute.3

3https://homes.cs.washington.edu/˜perelman/publications/pldi14-tds.zip 40 / 49

slide-41
SLIDE 41

Evaluation

◮ Three DSLs focused on end-user data transformation tasks.

◮ String transformations (FlashFill+extensions) ◮ Spreadsheet table transformations ◮ XML transformations

◮ Able to synthesize many examples from help forums in under

a minute.3

◮ Good news: test case sequences are very short (easy for user)

3https://homes.cs.washington.edu/˜perelman/publications/pldi14-tds.zip 41 / 49

slide-42
SLIDE 42

Evaluation

◮ Three DSLs focused on end-user data transformation tasks.

◮ String transformations (FlashFill+extensions) ◮ Spreadsheet table transformations ◮ XML transformations

◮ Able to synthesize many examples from help forums in under

a minute.3

◮ Good news: test case sequences are very short (easy for user) ◮ Bad news: test case sequences are very short (difficult to

evaluate usefulness of sequences)

3https://homes.cs.washington.edu/˜perelman/publications/pldi14-tds.zip 42 / 49

slide-43
SLIDE 43

Pex4Fun (now https://www.CodeHunt.com/)

domain expert intro CS DSL test cases player modifies program program done? generate new test case win game no yes

43 / 49

slide-44
SLIDE 44

Pex4Fun (now https://www.CodeHunt.com/)

domain expert intro CS DSL test cases sequence synthesize change program done? generate new test case win game no yes

44 / 49

slide-45
SLIDE 45

Comparison to human players

20 40 60 80 100 0 20 40 60 80 100 120 140 160 180 200 Synthesizer Time (seconds) User Time (seconds) 20 40 60 80 100 0 20 40 60 80 100 120 140 160 180 200 Synthesizer Time (seconds) User Time (seconds)

Completion times comparable to human players

45 / 49

slide-46
SLIDE 46

Research question

Hypothesis:

◮ Test sequence order matters. . . ◮ . . . but not too much.

46 / 49

slide-47
SLIDE 47

Slowdown due to reordering test case sequence

1 10 100 0.2 0.4 0.6 0.8 1 Normalized execution time Normalized inversions count

Robust to small reorderings, fails on larger reorderings

47 / 49

slide-48
SLIDE 48

Contributions

◮ Synthesis workflow inspired by

TDD

◮ Search strategy enabled by this

workflow, parameterized by a DSL

48 / 49

slide-49
SLIDE 49

Questions

49 / 49

slide-50
SLIDE 50

Backup slides

50 / 49

slide-51
SLIDE 51

Component-based synthesis example

Starting components:

◮ a+b ◮ 0 ◮ x ◮ y

Generated components (1 step):

◮ 0+b ◮ x+b ◮ y+b

Generated components (2 steps):

◮ 0+0 ◮ x+0 ◮ y+0 ◮ 0+x ◮ x+x ◮ y+x ◮ 0+y ◮ x+y ◮ y+y

51 / 49

slide-52
SLIDE 52

Component-based synthesis example

Starting components:

◮ a+b ◮ 0 ◮ x ◮ y

Generated components (1 step):

◮ 0+b ◮ x+b ◮ y+b

Generated components (2 steps):

◮ 0+0=0 ◮ x+0=x ◮ y+0=y ◮ 0+x=x ◮ x+x ◮ y+x ◮ 0+y=y ◮ x+y=y+x ◮ y+y

52 / 49

slide-53
SLIDE 53

Component-based synthesis example

Starting components:

◮ a+b ◮ 0 ◮ x ◮ y

Generated components (1 step):

◮ 0+b ◮ x+b ◮ y+b

Generated components (2 steps):

◮ 0+0=0 ◮ x+0=x ◮ y+0=y ◮ 0+x=x ◮ x+x ◮ y+x ◮ 0+y=y ◮ x+y=y+x ◮ y+y

53 / 49

slide-54
SLIDE 54

Component-based synthesis example

Starting components:

◮ a+b ◮ 0=[0,0] ◮ x=[10,-31] ◮ y=[-10,31]

Generated components (1 step):

◮ 0+b ◮ x+b ◮ y+b

Generated components (2 steps):

◮ 0+0=[0,0] ◮ x+0=[10,-31] ◮ y+0=[-10,31] ◮ 0+x=[10,-31] ◮ x+x=[20,-62] ◮ y+x=[0,0] ◮ 0+y=[-10,31] ◮ x+y=[0,0] ◮ y+y=[-20,62]

54 / 49

slide-55
SLIDE 55

Component-based synthesis example

Starting components:

◮ a+b ◮ 0=[0,0] ◮ x=[10,-31] ◮ y=[-10,31]

Generated components (1 step):

◮ 0+b ◮ x+b ◮ y+b

Generated components (2 steps):

◮ 0+0=[0,0] ◮ x+0=[10,-31] ◮ y+0=[-10,31] ◮ 0+x=[10,-31] ◮ x+x=[20,-62] ◮ y+x=[0,0] ◮ 0+y=[-10,31] ◮ x+y=[0,0] ◮ y+y=[-20,62]

55 / 49

slide-56
SLIDE 56

Loops

◮ Rule-based generation of test cases for loop body from test

cases for loop

56 / 49

slide-57
SLIDE 57

Loops

◮ Rule-based generation of test cases for loop body from test

cases for loop

◮ For loop example:

Factorial(1)=1 Factorial(2)=2 Factorial(3)=6 Factorial(4)=24 ⇒ Factorial body(2,1)=2 Factorial body(3,2)=6 Factorial body(4,6)=24

57 / 49

slide-58
SLIDE 58

Loops

◮ Rule-based generation of test cases for loop body from test

cases for loop

◮ For loop example:

Factorial(1)=1 Factorial(2)=2 Factorial(3)=6 Factorial(4)=24 ⇒ Factorial body(2,1)=2 Factorial body(3,2)=6 Factorial body(4,6)=24

◮ Array by-element example:

CSum([6,2,8],[4,3,7]) =[10,15,30] ⇒ CSum body(6,4,0,[])=10 CSum body(2,3,1,[10])=15 CSum body(8,7,2,[10,15])=30

58 / 49