trackler 2.0.8.38 → 2.0.8.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,117 @@
1
+ // +build ignore
2
+
3
+ package main
4
+
5
+ import (
6
+ "log"
7
+ "text/template"
8
+
9
+ "../../gen"
10
+ )
11
+
12
+ func main() {
13
+ t, err := template.New("").Parse(tmpl)
14
+ if err != nil {
15
+ log.Fatal(err)
16
+ }
17
+ var j js
18
+ if err := gen.Gen("bowling", &j, t); err != nil {
19
+ log.Fatal(err)
20
+ }
21
+ }
22
+
23
+ // The JSON structure we expect to be able to unmarshal into
24
+ type js struct {
25
+ Exercise string
26
+ Version string
27
+ Comments []string
28
+ Cases []OneCase
29
+ }
30
+
31
+ // template applied to above data structure generates the Go test cases
32
+
33
+ type OneCase struct {
34
+ Description string
35
+ Property string
36
+ PreviousRolls []int `json:"previous_rolls"`
37
+ Roll int
38
+ Expected interface{}
39
+ }
40
+
41
+ // ScoreTest and RollTest help determine which type of test case
42
+ // to generate in the template.
43
+ func (c OneCase) ScoreTest() bool { return c.Property == "score" }
44
+ func (c OneCase) RollTest() bool { return c.Property == "roll" }
45
+
46
+ func (c OneCase) Valid() bool {
47
+ valid, _, _ := determineExpected(c.Expected)
48
+ return valid
49
+ }
50
+
51
+ func (c OneCase) Score() int {
52
+ _, score, _ := determineExpected(c.Expected)
53
+ return score
54
+ }
55
+
56
+ func (c OneCase) ExplainText() string {
57
+ _, _, explainText := determineExpected(c.Expected)
58
+ return explainText
59
+ }
60
+
61
+ // determineExpected examines an .Expected interface{} object and determines
62
+ // whether a test case is valid(bool), has a score field, and/or has an expected error,
63
+ // returning valid, score, and error explanation text.
64
+ func determineExpected(expected interface{}) (bool, int, string) {
65
+ score, ok := expected.(float64)
66
+ if ok {
67
+ return ok, int(score), ""
68
+ }
69
+ m, ok := expected.(map[string]interface{})
70
+ if !ok {
71
+ return false, 0, ""
72
+ }
73
+ iError, ok := m["error"].(interface{})
74
+ if !ok {
75
+ return false, 0, ""
76
+ }
77
+ explainText, ok := iError.(string)
78
+ return false, 0, explainText
79
+ }
80
+
81
+ // Template to generate two sets of test cases, one for Score tests and one for Roll tests.
82
+ var tmpl = `package bowling
83
+
84
+ {{.Header}}
85
+
86
+ var scoreTestCases = []struct {
87
+ description string
88
+ previousRolls []int // bowling rolls to do before the Score() test
89
+ valid bool // true => no error, false => error expected
90
+ score int // when .valid == true, the expected score value
91
+ explainText string // when .valid == false, error explanation text
92
+ }{ {{range .J.Cases}}
93
+ {{if .ScoreTest}}{
94
+ {{printf "%q" .Description}},
95
+ {{printf "%#v" .PreviousRolls}},
96
+ {{printf "%v" .Valid}},
97
+ {{printf "%d" .Score}},
98
+ {{printf "%q" .ExplainText}},
99
+ },{{- end}}{{end}}
100
+ }
101
+
102
+ var rollTestCases = []struct {
103
+ description string
104
+ previousRolls []int // bowling rolls to do before the Roll(roll) test
105
+ valid bool // true => no error, false => error expected
106
+ roll int // pin count for the test roll
107
+ explainText string // when .valid == false, error explanation text
108
+ }{ {{range .J.Cases}}
109
+ {{if .RollTest}}{
110
+ {{printf "%q" .Description}},
111
+ {{printf "%#v" .PreviousRolls}},
112
+ {{printf "%v" .Valid}},
113
+ {{printf "%d" .Roll}},
114
+ {{printf "%q" .ExplainText}},
115
+ },{{- end}}{{end}}
116
+ }
117
+ `
@@ -1,7 +1,8 @@
1
1
  package leap
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: be6fa53 leap: Rewrite the test cases and their descriptions
4
+ // Commit: cc65ebe leap: Fix canonical-data.json formatting
5
+ // x-common version: 1.0.0
5
6
 
6
7
  var testCases = []struct {
7
8
  year int
@@ -32,9 +32,7 @@ type js struct {
32
32
  // template applied to above data structure generates the Go test cases
33
33
  var tmpl = `package leap
34
34
 
35
- // Source: {{.Ori}}
36
- {{if .Commit}}// Commit: {{.Commit}}
37
- {{end}}
35
+ {{.Header}}
38
36
 
39
37
  var testCases = []struct {
40
38
  year int
@@ -32,6 +32,27 @@ var dirMetadata string
32
32
  // Falls back to the present working directory.
33
33
  var dirProblem string
34
34
 
35
+ // Header tells how the test data was generated, for display in the header of cases_test.go
36
+ type Header struct {
37
+ // Ori is a deprecated short name for Origin.
38
+ // TODO: Remove Ori once everything switches to Origin.
39
+ Ori string
40
+ Origin string
41
+ Commit string
42
+ Version string
43
+ }
44
+
45
+ func (h Header) String() string {
46
+ s := fmt.Sprintf("// Source: %s\n", h.Origin)
47
+ if h.Commit != "" {
48
+ s += fmt.Sprintf("// Commit: %s\n", h.Commit)
49
+ }
50
+ if h.Version != "" {
51
+ s += fmt.Sprintf("// x-common version: %s\n", h.Version)
52
+ }
53
+ return s
54
+ }
55
+
35
56
  func init() {
36
57
  if _, path, _, ok := runtime.Caller(0); ok {
37
58
  dirMetadata = filepath.Join(path, "..", "..", "..", "x-common")
@@ -50,7 +71,7 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
50
71
  }
51
72
  jFile := filepath.Join("exercises", exercise, "canonical-data.json")
52
73
  // find and read the json source file
53
- jPath, jOri, jCommit := getPath(jFile)
74
+ jPath, jOrigin, jCommit := getPath(jFile)
54
75
  jSrc, err := ioutil.ReadFile(filepath.Join(jPath, jFile))
55
76
  if err != nil {
56
77
  return err
@@ -65,12 +86,24 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
65
86
  return fmt.Errorf(`unexpected data structure: %v`, err)
66
87
  }
67
88
 
89
+ // These fields are guaranteed to be in every problem
90
+ var commonMetadata struct {
91
+ Version string
92
+ }
93
+ if err := json.Unmarshal(jSrc, &commonMetadata); err != nil {
94
+ return fmt.Errorf(`Didn't contain version: %v`, err)
95
+ }
96
+
68
97
  // package up a little meta data
69
98
  d := struct {
70
- Ori string
71
- Commit string
72
- J interface{}
73
- }{jOri, jCommit, j}
99
+ Header
100
+ J interface{}
101
+ }{Header{
102
+ Ori: jOrigin,
103
+ Origin: jOrigin,
104
+ Commit: jCommit,
105
+ Version: commonMetadata.Version,
106
+ }, j}
74
107
 
75
108
  // render the Go test cases
76
109
  var b bytes.Buffer
@@ -86,7 +119,7 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
86
119
  return ioutil.WriteFile(filepath.Join(dirProblem, "cases_test.go"), src, 0666)
87
120
  }
88
121
 
89
- func getPath(jFile string) (jPath, jOri, jCommit string) {
122
+ func getPath(jFile string) (jPath, jOrigin, jCommit string) {
90
123
  // Ideally draw from a .json which is pulled from the official x-common
91
124
  // repository. For development however, accept a file in current directory
92
125
  // if there is no .json in source control. Also allow an override in any
@@ -0,0 +1,29 @@
1
+ The `exercise-gen.pl6` file can be used in the following ways:
2
+ * From within the directory of the exercise you wish to generate a test for.
3
+ * With arguments specifying which exercises you want to generate tests for.
4
+ e.g. `./exercise-gen.pl6 hello-world leap`
5
+ * With the argument `--all` to run the generator for all exercises.
6
+ i.e `./exercise-gen.pl6 --all`
7
+
8
+ The generator will retrieve data from an `example.yaml` file within
9
+ each exercise directory, and use the contained information to generate
10
+ test files using `templates/test.mustache`. If it finds a
11
+ `canonical-data.json` file in `x-common` for the exercise in
12
+ question it will be included.
13
+
14
+ Example of a yaml file:
15
+ ```yaml
16
+ exercise: MyExercise
17
+ version: 1
18
+ plan: 10
19
+ modules:
20
+ - use: Data::Dump
21
+ - use: Foo::Bar
22
+ imports: 'MyClass &my-subroutine'
23
+ methods: 'foo bar'
24
+ tests: |
25
+ ok True, 'Perl 6 code here';
26
+ pass;
27
+ ```
28
+
29
+ You must have `Template::Mustache` and `YAMLish` to run `exercise-gen.pl6`.
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env perl6
2
+ use v6;
3
+ use Template::Mustache;
4
+ use YAMLish;
5
+
6
+ my $base-dir = $?FILE.IO.resolve.parent.parent;
7
+ my @exercises;
8
+
9
+ if @*ARGS {
10
+ if @*ARGS[0] eq '--all' {
11
+ push @exercises, $_.basename for $base-dir.child('exercises').dir;
12
+ } else {
13
+ @exercises = @*ARGS;
14
+ }
15
+ } else {
16
+ say 'No args given; working in current directory.';
17
+ if 'example.yaml'.IO ~~ :f {
18
+ push @exercises, $*CWD.IO.basename;
19
+ } else {
20
+ say 'example.yaml not found; exiting.';
21
+ exit;
22
+ }
23
+ }
24
+
25
+ for @exercises -> $exercise {
26
+ my $exercise-dir = $base-dir.child("exercises/$exercise");
27
+ next if (my $yaml = $exercise-dir.child('example.yaml')) !~~ :f;
28
+ my $cdata = $base-dir.child("x-common/exercises/$exercise/canonical-data.json");
29
+ my %data = load-yaml $yaml.slurp;
30
+ %data<cdata> = {:json($cdata.slurp)} if $cdata ~~ :f;
31
+
32
+ spurt (my $test = $exercise-dir.child("$exercise.t")),
33
+ Template::Mustache.render($base-dir.child('templates/test.mustache').slurp, %data);
34
+ $test.chmod(0o755);
35
+ say "$exercise generated.";
36
+ }
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "ignored": [
13
13
  "docs",
14
+ "templates",
14
15
  "x-common",
15
16
  "img"
16
17
  ],
@@ -0,0 +1,19 @@
1
+ exercise: HelloWorld
2
+ version: 2
3
+ plan: 3
4
+ imports: '&hello'
5
+ tests: |
6
+ #`[Go through the cases (hiding at the bottom of this file)
7
+ and check that &hello gives us the correct response.]
8
+ is &::('hello')(), |.<expected description> for @($c-data<cases>);
9
+
10
+ exercise_comment: The name of this exercise.
11
+ module_comment: "%*ENV<EXERCISM> is for tests not directly for the exercise, don't worry about these :)"
12
+ version_comment: The version we will be matching against the exercise.
13
+ plan_comment: This is how many tests we expect to run.
14
+ use_test_comment: Check that the module can be use-d.
15
+ version_test_comment: "If the exercise is updated, we want to make sure other people testing\nyour code don't think you've made a mistake if things have changed!"
16
+ imports_comment: Import '&hello' from 'HelloWorld'
17
+ cdata_test_comment: Ignore this for your exercise! Tells Exercism folks when exercise cases become out of date.
18
+ done_testing_comment: There are no more tests after this :)
19
+ INIT_comment: "'INIT' is a phaser, it makes sure that the test data is available before everything else\nstarts running (otherwise we'd have to shove the test data into the middle of the file!)"
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env perl6
2
+ use v6;{{=#`{{ }}=}}#`{{! Mustache tags double up as Perl 6 embedded comments}}
3
+ use Test;
4
+ use lib #`{{#cdata}}my $dir = #`{{/cdata}}$?FILE.IO.dirname;#`{{#lib_comment}} #`[#`{{&lib_comment}}]#`{{/lib_comment}}
5
+ #`{{#cdata}}use JSON::Tiny;
6
+ #`{{/cdata}}#`{{#modules}}use #`{{&use}};
7
+ #`{{/modules}}
8
+
9
+ my $exercise#`{{#exercise}} = '#`{{&exercise}}'#`{{/exercise}};#`{{#exercise_comment}} #`[#`{{&exercise_comment}}]#`{{/exercise_comment}}
10
+ my $version#`{{#version}} = v#`{{&version}}#`{{/version}};#`{{#version_comment}} #`[#`{{&version_comment}}]#`{{/version_comment}}
11
+ my $module = %*ENV<EXERCISM> ?? 'Example' !! $exercise;#`{{#module_comment}} #`[#`{{&module_comment}}]#`{{/module_comment}}#`{{#plan}}
12
+ plan #`{{&plan}};#`{{#plan_comment}} #`[#`{{&plan_comment}}]#`{{/plan_comment}}#`{{/plan}}
13
+ #`{{#use_test_comment}}
14
+
15
+ #`[#`{{&use_test_comment}}]#`{{/use_test_comment}}
16
+ use-ok $module or bail-out;
17
+ require ::($module);
18
+ #`{{#version_test_comment}}
19
+
20
+ #`[#`{{&version_test_comment}}]#`{{/version_test_comment}}
21
+ if ::($exercise).^ver !~~ $version {
22
+ warn "\nExercise version mismatch. Further tests may fail!"
23
+ ~ "\n$exercise is $(::($exercise).^ver.gist). "
24
+ ~ "Test is $($version.gist).\n";
25
+ bail-out 'Example version must match test version.' if %*ENV<EXERCISM>;
26
+ }
27
+ #`{{#imports}}#`{{#imports_comment}}
28
+ #`[#`{{&imports_comment}}]#`{{/imports_comment}}
29
+ require ::($module) <#`{{&imports}}>;
30
+ #`{{/imports}}#`{{#methods}}#`{{#methods_comment}}
31
+ #`[#`{{&methods_comment}}]#`{{/methods_comment}}
32
+ subtest 'Class methods', {
33
+ ok ::($exercise).can($_), $_ for <#`{{&methods}}>;
34
+ }
35
+ #`{{/methods}}#`{{#cdata}}
36
+ my $c-data;#`{{/cdata}}
37
+ #`{{&tests}}#`{{#cdata}}#`{{#cdata_test_comment}}
38
+ #`[#`{{&cdata_test_comment}}]#`{{/cdata_test_comment}}
39
+ if %*ENV<EXERCISM> && (my $c-data-file =
40
+ "$dir/../../x-common/exercises/{$dir.IO.resolve.basename}/canonical-data.json".IO.resolve) ~~ :f
41
+ { is-deeply $c-data, from-json($c-data-file.slurp), 'canonical-data' } else { skip }
42
+ #`{{/cdata}}
43
+
44
+ done-testing;#`{{#done_testing_comment}} #`[#`{{&done_testing_comment}}]#`{{/done_testing_comment}}#`{{#cdata}}
45
+ #`{{#INIT_comment}}
46
+
47
+ #`[#`{{&INIT_comment}}]#`{{/INIT_comment}}
48
+ INIT {
49
+ $c-data := from-json q:to/END/;
50
+
51
+ #`{{&json}}
52
+ END
53
+ }#`{{/cdata}}
@@ -18,7 +18,7 @@ install:
18
18
  - pip install -r requirements-travis.txt
19
19
 
20
20
  before_script:
21
- - flake8 ./exercises/ --max-line-length=99 --select=E,W
21
+ - flake8
22
22
 
23
23
  script:
24
24
  - ./test/check-exercises.py
@@ -34,13 +34,9 @@ python test/check-exercises.py
34
34
 
35
35
  ## Code Style
36
36
 
37
- The Python code in this repo is meant to largely obey the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/).
37
+ The Python code in this repo is meant to follow the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/).
38
38
 
39
- This repo uses [flake8](http://flake8.readthedocs.org/en/latest/) to enforce the coding standard. When you submit a PR, it needs to pass the flake8 tool with no warnings, or it won't be accepted. Here are the settings used by the build system:
40
-
41
- ```
42
- flake8 [your-code-here.py] --max-line-length=99 --select=E,W
43
- ```
39
+ This repo uses [flake8](http://flake8.readthedocs.org/en/latest/) with default settings to enforce the coding standard. When you submit a PR, it needs to pass the flake8 tool with no warnings, or it won't be accepted.
44
40
 
45
41
  ## Pull Requests
46
42
 
@@ -101,6 +101,15 @@
101
101
  "topics": [
102
102
  ]
103
103
  },
104
+ {
105
+ "slug": "rotational-cipher",
106
+ "difficulty": 1,
107
+ "topics": [
108
+ "strings",
109
+ "logic",
110
+ "control-flow (loops)"
111
+ ]
112
+ },
104
113
  {
105
114
  "slug": "difference-of-squares",
106
115
  "difficulty": 1,
@@ -3,69 +3,73 @@ import unittest
3
3
  from anagram import detect_anagrams
4
4
 
5
5
 
6
+ # test cases adapted from `x-common//canonical-data.json` @ version: 1.0.1
7
+
6
8
  class AnagramTests(unittest.TestCase):
7
9
  def test_no_matches(self):
8
- self.assertEqual(
9
- [],
10
- detect_anagrams('diaper', 'hello world zombies pants'.split())
11
- )
10
+ candidates = ["hello", "world", "zombies", "pants"]
11
+ self.assertEqual(detect_anagrams("diaper", candidates), [])
12
12
 
13
- def test_detect_simple_anagram(self):
14
- self.assertEqual(
15
- ['tan'],
16
- detect_anagrams('ant', 'tan stand at'.split())
17
- )
13
+ def test_detects_simple_anagram(self):
14
+ candidates = ["tan", "stand", "at"]
15
+ self.assertEqual(detect_anagrams("ant", candidates), ["tan"])
18
16
 
19
- def test_detect_multiple_anagrams(self):
20
- self.assertEqual(
21
- ['stream', 'maters'],
22
- detect_anagrams('master', 'stream pigeon maters'.split())
23
- )
17
+ def test_does_not_detect_false_positives(self):
18
+ self.assertEqual(detect_anagrams("galea", ["eagle"]), [])
24
19
 
25
- def test_does_not_confuse_different_duplicates(self):
20
+ def test_detects_two_anagrams(self):
21
+ candidates = ["stream", "pigeon", "maters"]
26
22
  self.assertEqual(
27
- [],
28
- detect_anagrams('galea', ['eagle'])
29
- )
23
+ detect_anagrams("master", candidates), ["stream", "maters"])
30
24
 
31
- def test_eliminate_anagram_subsets(self):
32
- self.assertEqual(
33
- [],
34
- detect_anagrams('good', 'dog goody'.split())
35
- )
25
+ def test_does_not_detect_anagram_subsets(self):
26
+ self.assertEqual(detect_anagrams("good", ["dog", "goody"]), [])
36
27
 
37
- def test_detect_anagram(self):
38
- self.assertEqual(
39
- ['inlets'],
40
- detect_anagrams('listen', 'enlists google inlets banana'.split())
41
- )
28
+ def test_detects_anagram(self):
29
+ candidates = ["enlists", "google", "inlets", "banana"]
30
+ self.assertEqual(detect_anagrams("listen", candidates), ["inlets"])
42
31
 
43
- def test_multiple_anagrams(self):
32
+ def test_detects_three_anagrams(self):
33
+ candidates = [
34
+ "gallery", "ballerina", "regally", "clergy", "largely", "leading"
35
+ ]
44
36
  self.assertEqual(
45
- 'gallery regally largely'.split(),
46
- detect_anagrams(
47
- 'allergy',
48
- 'gallery ballerina regally clergy largely leading'.split()
49
- )
50
- )
51
-
52
- def test_anagrams_are_case_insensitive(self):
37
+ detect_anagrams("allergy", candidates),
38
+ ["gallery", "regally", "largely"])
39
+
40
+ def test_does_not_detect_identical_words(self):
41
+ candidates = ["corn", "dark", "Corn", "rank", "CORN", "cron", "park"]
42
+ self.assertEqual(detect_anagrams("corn", candidates), ["cron"])
43
+
44
+ def test_does_not_detect_non_anagrams_with_identical_checksum(self):
45
+ self.assertEqual(detect_anagrams("mass", ["last"]), [])
46
+
47
+ def test_detects_anagrams_case_insensitively(self):
48
+ candidates = ["cashregister", "Carthorse", "radishes"]
53
49
  self.assertEqual(
54
- ['Carthorse'],
55
- detect_anagrams('Orchestra',
56
- 'cashregister Carthorse radishes'.split())
57
- )
50
+ detect_anagrams("Orchestra", candidates), ["Carthorse"])
58
51
 
59
- def test_same_word_isnt_anagram(self):
52
+ def test_detects_anagrams_using_case_insensitive_subjec(self):
53
+ candidates = ["cashregister", "carthorse", "radishes"]
60
54
  self.assertEqual(
61
- [],
62
- detect_anagrams('banana', ['banana'])
63
- )
55
+ detect_anagrams("Orchestra", candidates), ["carthorse"])
64
56
 
57
+ def test_detects_anagrams_using_case_insensitive_possible_matches(self):
58
+ candidates = ["cashregister", "Carthorse", "radishes"]
65
59
  self.assertEqual(
66
- [],
67
- detect_anagrams('go', 'go Go GO'.split())
68
- )
60
+ detect_anagrams("orchestra", candidates), ["Carthorse"])
61
+
62
+ def test_does_not_detect_a_word_as_its_own_anagram(self):
63
+ self.assertEqual(detect_anagrams("banana", ["Banana"]), [])
64
+
65
+ def test_does_not_detect_a_anagram_if_the_original_word_is_repeated(self):
66
+ self.assertEqual(detect_anagrams("go", ["go Go GO"]), [])
67
+
68
+ def test_anagrams_must_use_all_letters_exactly_once(self):
69
+ self.assertEqual(detect_anagrams("tapper", ["patter"]), [])
70
+
71
+ def test_capital_word_is_not_own_anagram(self):
72
+ self.assertEqual(detect_anagrams("BANANA", ["Banana"]), [])
69
73
 
70
74
 
71
75
  if __name__ == '__main__':