moz-fluent-linter 0.4.7__tar.gz → 0.4.8__tar.gz

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.
Files changed (24) hide show
  1. {moz_fluent_linter-0.4.7/src/moz_fluent_linter.egg-info → moz_fluent_linter-0.4.8}/PKG-INFO +4 -3
  2. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/README.md +1 -1
  3. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/setup.cfg +1 -1
  4. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/setup.py +1 -0
  5. moz_fluent_linter-0.4.8/src/fluent_linter/__init__.py +1 -0
  6. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/fluent_linter/linter.py +57 -39
  7. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8/src/moz_fluent_linter.egg-info}/PKG-INFO +4 -3
  8. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_banned_words.py +6 -4
  9. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_brands.py +6 -5
  10. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_comments.py +6 -4
  11. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_comments_variables.py +6 -4
  12. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_ids.py +6 -4
  13. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_placeable_style.py +6 -4
  14. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_syntax.py +6 -4
  15. moz_fluent_linter-0.4.8/tests/test_typography.py +222 -0
  16. moz_fluent_linter-0.4.7/src/fluent_linter/__init__.py +0 -1
  17. moz_fluent_linter-0.4.7/tests/test_typography.py +0 -112
  18. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/LICENSE +0 -0
  19. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/pyproject.toml +0 -0
  20. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/SOURCES.txt +0 -0
  21. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/dependency_links.txt +0 -0
  22. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/entry_points.txt +0 -0
  23. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/requires.txt +0 -0
  24. {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: moz-fluent-linter
3
- Version: 0.4.7
3
+ Version: 0.4.8
4
4
  Summary: Linter package used to check Fluent files
5
5
  Home-page: https://github.com/mozilla-l10n/moz-fluent-linter
6
6
  Author: Francesco Lodolo
@@ -18,6 +18,7 @@ License-File: LICENSE
18
18
  Requires-Dist: fluent.syntax~=0.19.0
19
19
  Requires-Dist: pyyaml
20
20
  Requires-Dist: six
21
+ Dynamic: license-file
21
22
 
22
23
  # Fluent Linter
23
24
 
@@ -41,7 +42,7 @@ Using [pre-commit](https://pre-commit.com/), add this to the `.pre-commit-config
41
42
  ```yaml
42
43
  repos:
43
44
  - repo: https://github.com/mozilla-l10n/moz-fluent-linter
44
- rev: v0.4.7
45
+ rev: v0.4.8
45
46
  hooks:
46
47
  - id: fluent_linter
47
48
  files: \.ftl$
@@ -20,7 +20,7 @@ Using [pre-commit](https://pre-commit.com/), add this to the `.pre-commit-config
20
20
  ```yaml
21
21
  repos:
22
22
  - repo: https://github.com/mozilla-l10n/moz-fluent-linter
23
- rev: v0.4.7
23
+ rev: v0.4.8
24
24
  hooks:
25
25
  - id: fluent_linter
26
26
  files: \.ftl$
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = moz-fluent-linter
3
- version = 0.4.7
3
+ version = 0.4.8
4
4
  author = Francesco Lodolo
5
5
  author_email = flod@mozilla.com
6
6
  description = Linter package used to check Fluent files
@@ -1,4 +1,5 @@
1
1
  from setuptools import setup
2
2
 
3
+
3
4
  if __name__ == "__main__":
4
5
  setup()
@@ -0,0 +1 @@
1
+ version = "0.4.8"
@@ -5,15 +5,19 @@
5
5
  # This script is largely based on the Fluent Linter used in mozilla-central
6
6
  # https://firefox-source-docs.mozilla.org/code-quality/lint/linters/fluent-lint.html
7
7
 
8
- from fluent.syntax import ast, parse, serializer, visitor
9
- from html.parser import HTMLParser
10
8
  import argparse
11
9
  import bisect
12
10
  import os
13
11
  import re
14
12
  import sys
13
+
14
+ from html.parser import HTMLParser
15
+
15
16
  import yaml
16
17
 
18
+ from fluent.syntax import ast, parse, serializer, visitor
19
+
20
+
17
21
  try:
18
22
  from fluent_linter import version
19
23
  except Exception:
@@ -160,31 +164,42 @@ class Linter(visitor.Visitor):
160
164
  f" hard-coded brand names ({', '.join(found_brands)})",
161
165
  )
162
166
 
163
- if self.apostrophe_re.search(cleaned_str):
164
- if not self.exclude_message("TE01", message_id):
165
- self.add_error(
166
- node,
167
- message_id,
168
- "TE01",
169
- "Strings with apostrophes should use foo\u2019s instead of foo's.",
170
- )
171
- if self.incorrect_apostrophe_re.search(cleaned_str):
172
- if not self.exclude_message("TE02", message_id):
173
- self.add_error(
174
- node,
175
- message_id,
176
- "TE02",
177
- "Strings with apostrophes should use foo\u2019s instead of foo\u2018s.",
178
- )
179
- if self.single_quote_re.search(cleaned_str):
180
- if not self.exclude_message("TE03", message_id):
181
- self.add_error(
182
- node,
183
- message_id,
184
- "TE03",
185
- "Single-quoted strings should use Unicode \u2018foo\u2019 instead of 'foo'.",
186
- )
187
- if self.double_quote_re.search(cleaned_str):
167
+ if (
168
+ self.config.get("TE01", {}).get("enabled", True)
169
+ and self.apostrophe_re.search(cleaned_str)
170
+ and not self.exclude_message("TE01", message_id)
171
+ ):
172
+ self.add_error(
173
+ node,
174
+ message_id,
175
+ "TE01",
176
+ "Strings with apostrophes should use foo\u2019s instead of foo's.",
177
+ )
178
+ if (
179
+ self.config.get("TE02", {}).get("enabled", True)
180
+ and self.incorrect_apostrophe_re.search(cleaned_str)
181
+ and not self.exclude_message("TE02", message_id)
182
+ ):
183
+ self.add_error(
184
+ node,
185
+ message_id,
186
+ "TE02",
187
+ "Strings with apostrophes should use foo\u2019s instead of foo\u2018s.",
188
+ )
189
+ if (
190
+ self.config.get("TE03", {}).get("enabled", True)
191
+ and self.single_quote_re.search(cleaned_str)
192
+ and not self.exclude_message("TE03", message_id)
193
+ ):
194
+ self.add_error(
195
+ node,
196
+ message_id,
197
+ "TE03",
198
+ "Single-quoted strings should use Unicode \u2018foo\u2019 instead of 'foo'.",
199
+ )
200
+ if self.config.get("TE04", {}).get(
201
+ "enabled", True
202
+ ) and self.double_quote_re.search(cleaned_str):
188
203
  # Ignore parameterized terms and other functions
189
204
  for regex in self.ftl_syntax_re:
190
205
  cleaned_str = regex.sub("", cleaned_str)
@@ -198,15 +213,18 @@ class Linter(visitor.Visitor):
198
213
  "TE04",
199
214
  'Double-quoted strings should use Unicode \u201cfoo\u201d instead of "foo".',
200
215
  )
201
- if self.ellipsis_re.search(cleaned_str):
202
- if not self.exclude_message("TE05", message_id):
203
- self.add_error(
204
- node,
205
- message_id,
206
- "TE05",
207
- "Strings with an ellipsis should use the Unicode \u2026 character"
208
- " instead of three periods",
209
- )
216
+ if (
217
+ self.config.get("TE05", {}).get("enabled", True)
218
+ and self.ellipsis_re.search(cleaned_str)
219
+ and not self.exclude_message("TE05", message_id)
220
+ ):
221
+ self.add_error(
222
+ node,
223
+ message_id,
224
+ "TE05",
225
+ "Strings with an ellipsis should use the Unicode \u2026 character"
226
+ " instead of three periods",
227
+ )
210
228
 
211
229
  def generic_visit(self, node):
212
230
  node_name = type(node).__name__
@@ -418,9 +436,9 @@ class Linter(visitor.Visitor):
418
436
  and not self.config["PS01"]["disabled"]
419
437
  and type(node.expression) not in [ast.SelectExpression]
420
438
  ):
421
- if type(node.expression) == ast.VariableReference:
439
+ if isinstance(node.expression, ast.VariableReference):
422
440
  placeable_name = f"${node.expression.id.name}"
423
- elif type(node.expression) == ast.TermReference:
441
+ elif isinstance(node.expression, ast.TermReference):
424
442
  placeable_name = f"-{node.expression.id.name}"
425
443
  else:
426
444
  placeable_name = node.expression.id.name
@@ -455,7 +473,7 @@ class Linter(visitor.Visitor):
455
473
  # Store the variable used for the SelectExpression, excluding functions
456
474
  # like PLATFORM()
457
475
  if (
458
- type(node.selector) == ast.VariableReference
476
+ isinstance(node.selector, ast.VariableReference)
459
477
  and node.selector.id.name not in self.state["variables"]
460
478
  ):
461
479
  self.state["variables"].append(node.selector.id.name)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: moz-fluent-linter
3
- Version: 0.4.7
3
+ Version: 0.4.8
4
4
  Summary: Linter package used to check Fluent files
5
5
  Home-page: https://github.com/mozilla-l10n/moz-fluent-linter
6
6
  Author: Francesco Lodolo
@@ -18,6 +18,7 @@ License-File: LICENSE
18
18
  Requires-Dist: fluent.syntax~=0.19.0
19
19
  Requires-Dist: pyyaml
20
20
  Requires-Dist: six
21
+ Dynamic: license-file
21
22
 
22
23
  # Fluent Linter
23
24
 
@@ -41,7 +42,7 @@ Using [pre-commit](https://pre-commit.com/), add this to the `.pre-commit-config
41
42
  ```yaml
42
43
  repos:
43
44
  - repo: https://github.com/mozilla-l10n/moz-fluent-linter
44
- rev: v0.4.7
45
+ rev: v0.4.8
45
46
  hooks:
46
47
  - id: fluent_linter
47
48
  files: \.ftl$
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestBannedWords(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "file.ftl", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testCO01(self):
16
18
  content = """
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestBrands(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "file.ftl", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testCO01(self):
16
18
  content = """
@@ -82,7 +84,6 @@ good-account2 = Set up your { -brand-short-name } Account.
82
84
 
83
85
  config = {"CO01": {"enabled": True, "brands": ["Monitor"], "exclusions": {}}}
84
86
  results = self.checkContent(config, content)
85
- print("\n".join(results))
86
87
  self.assertEqual(len(results), 1)
87
88
  self.assertTrue("bad-monitor" in results[0])
88
89
  self.assertTrue("good-monitor" not in results[0])
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestComments(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "path", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testGC01(self):
16
18
  content = """
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestCommentVariables(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "path", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testVC01(self):
16
18
  content = """
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestIDs(unittest.TestCase):
7
9
  def checkContent(self, path, root, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  path, root, config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testID01(self):
16
18
  content = """
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestPlaceableStyle(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "path", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testPS01_valid(self):
16
18
  content = """
@@ -1,16 +1,18 @@
1
1
  import unittest
2
- from src.fluent_linter import linter
2
+
3
3
  from fluent.syntax import parse
4
4
 
5
+ from src.fluent_linter import linter
6
+
5
7
 
6
8
  class TestSyntax(unittest.TestCase):
7
9
  def checkContent(self, config, content):
8
- l = linter.Linter(
10
+ ftl_linter = linter.Linter(
9
11
  "path", "root", config, content, linter.get_offsets_and_lines(content)
10
12
  )
11
- l.visit(parse(content))
13
+ ftl_linter.visit(parse(content))
12
14
 
13
- return l.results
15
+ return ftl_linter.results
14
16
 
15
17
  def testSY01(self):
16
18
  content = """
@@ -0,0 +1,222 @@
1
+ import unittest
2
+
3
+ from fluent.syntax import parse
4
+
5
+ from src.fluent_linter import linter
6
+
7
+
8
+ class TestTypography(unittest.TestCase):
9
+ def checkContent(self, config, content):
10
+ ftl_linter = linter.Linter(
11
+ "path", "root", config, content, linter.get_offsets_and_lines(content)
12
+ )
13
+ ftl_linter.visit(parse(content))
14
+
15
+ return ftl_linter.results
16
+
17
+ def testTE01(self):
18
+ content = """
19
+ foo = bar's bar
20
+ """
21
+ results = self.checkContent({}, content)
22
+ self.assertEqual(len(results), 1)
23
+ self.assertTrue("TE01" in results[0])
24
+ self.assertTrue("foo" in results[0])
25
+
26
+ # Check exclusions
27
+ config = {"TE01": {"exclusions": {"messages": ["foo"]}}}
28
+ results = self.checkContent(config, content)
29
+ self.assertEqual(len(results), 0)
30
+
31
+ content = """
32
+ foo = bar ' bar
33
+ """
34
+ results = self.checkContent({}, content)
35
+ self.assertEqual(len(results), 0)
36
+
37
+ def testTE02(self):
38
+ content = """
39
+ foo = bar‘s bar
40
+ """
41
+ results = self.checkContent({}, content)
42
+ self.assertEqual(len(results), 1)
43
+ self.assertTrue("TE02" in results[0])
44
+ self.assertTrue("foo" in results[0])
45
+
46
+ # Check exclusions
47
+ config = {"TE02": {"exclusions": {"messages": ["foo"]}}}
48
+ results = self.checkContent(config, content)
49
+ self.assertEqual(len(results), 0)
50
+
51
+ content = """
52
+ foo = bar ‘ bar
53
+ """
54
+ results = self.checkContent({}, content)
55
+ self.assertEqual(len(results), 0)
56
+
57
+ def testTE03(self):
58
+ content = """
59
+ foo = bar 'bar' bar
60
+ """
61
+ results = self.checkContent({}, content)
62
+ self.assertEqual(len(results), 2)
63
+ self.assertTrue("TE01" in results[0])
64
+ self.assertTrue("TE03" in results[1])
65
+ self.assertTrue("foo" in results[0])
66
+
67
+ # Check exclusions
68
+ config = {
69
+ "TE01": {"exclusions": {"messages": ["foo"]}},
70
+ "TE03": {"exclusions": {"messages": ["foo"]}},
71
+ }
72
+ results = self.checkContent(config, content)
73
+ self.assertEqual(len(results), 0)
74
+
75
+ def testTE04(self):
76
+ content = """
77
+ foo = bar "bar" bar
78
+ # This shouldn't trigger an error
79
+ foo1 = { -someterm(capitalization: "uppercase") }
80
+ foo-datetime = Test: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
81
+ foo-number = { NUMBER($mem, maxFractionalUnits: 2) } MB
82
+ foo-empty = { "" }
83
+ foo-space = { "" } test
84
+ foo-curly1 = { "{" } test
85
+ foo-curly2 = { "}" } test
86
+ """
87
+ results = self.checkContent({}, content)
88
+ self.assertEqual(len(results), 1)
89
+ self.assertTrue("TE04" in results[0])
90
+ self.assertTrue("foo" in results[0])
91
+
92
+ # Check exclusions
93
+ config = {"TE04": {"exclusions": {"messages": ["foo"]}}}
94
+ results = self.checkContent(config, content)
95
+ self.assertEqual(len(results), 0)
96
+
97
+ def testTE05(self):
98
+ content = """
99
+ foo = bar...
100
+ """
101
+ results = self.checkContent({}, content)
102
+ self.assertEqual(len(results), 1)
103
+ self.assertTrue("TE05" in results[0])
104
+
105
+ # Check exclusions
106
+ config = {"TE05": {"exclusions": {"messages": ["foo"]}}}
107
+ results = self.checkContent(config, content)
108
+ self.assertEqual(len(results), 0)
109
+
110
+ content = """
111
+ foo = bar…
112
+ """
113
+ results = self.checkContent({}, content)
114
+ self.assertEqual(len(results), 0)
115
+
116
+ def testTE01Disabled(self):
117
+ """Test that TE01 can be disabled with enabled: false"""
118
+ content = """
119
+ foo = bar's bar
120
+ """
121
+ # Rule enabled by default - should trigger error
122
+ results = self.checkContent({}, content)
123
+ self.assertEqual(len(results), 1)
124
+ self.assertTrue("TE01" in results[0])
125
+
126
+ # Rule explicitly disabled - should not trigger error
127
+ config = {"TE01": {"enabled": False}}
128
+ results = self.checkContent(config, content)
129
+ self.assertEqual(len(results), 0)
130
+
131
+ # Rule explicitly enabled - should trigger error
132
+ config = {"TE01": {"enabled": True}}
133
+ results = self.checkContent(config, content)
134
+ self.assertEqual(len(results), 1)
135
+ self.assertTrue("TE01" in results[0])
136
+
137
+ def testTE02Disabled(self):
138
+ """Test that TE02 can be disabled with enabled: false"""
139
+ content = """
140
+ foo = bar‘s bar
141
+ """
142
+ # Rule enabled by default - should trigger error
143
+ results = self.checkContent({}, content)
144
+ self.assertEqual(len(results), 1)
145
+ self.assertTrue("TE02" in results[0])
146
+
147
+ # Rule explicitly disabled - should not trigger error
148
+ config = {"TE02": {"enabled": False}}
149
+ results = self.checkContent(config, content)
150
+ self.assertEqual(len(results), 0)
151
+
152
+ # Rule explicitly enabled - should trigger error
153
+ config = {"TE02": {"enabled": True}}
154
+ results = self.checkContent(config, content)
155
+ self.assertEqual(len(results), 1)
156
+ self.assertTrue("TE02" in results[0])
157
+
158
+ def testTE03Disabled(self):
159
+ """Test that TE03 can be disabled with enabled: false"""
160
+ content = """
161
+ foo = bar 'test' bar
162
+ """
163
+ # Rule enabled by default - should trigger errors (TE01 and TE03)
164
+ results = self.checkContent({}, content)
165
+ self.assertEqual(len(results), 2)
166
+ self.assertTrue("TE01" in results[0])
167
+ self.assertTrue("TE03" in results[1])
168
+
169
+ # TE03 explicitly disabled - should only get TE01 error
170
+ config = {"TE03": {"enabled": False}}
171
+ results = self.checkContent(config, content)
172
+ self.assertEqual(len(results), 1)
173
+ self.assertTrue("TE01" in results[0])
174
+
175
+ # TE03 explicitly enabled - should get both errors
176
+ config = {"TE03": {"enabled": True}}
177
+ results = self.checkContent(config, content)
178
+ self.assertEqual(len(results), 2)
179
+ self.assertTrue("TE01" in results[0])
180
+ self.assertTrue("TE03" in results[1])
181
+
182
+ def testTE04Disabled(self):
183
+ """Test that TE04 can be disabled with enabled: false"""
184
+ content = """
185
+ foo = bar "test" bar
186
+ """
187
+ # Rule enabled by default - should trigger error
188
+ results = self.checkContent({}, content)
189
+ self.assertEqual(len(results), 1)
190
+ self.assertTrue("TE04" in results[0])
191
+
192
+ # Rule explicitly disabled - should not trigger error
193
+ config = {"TE04": {"enabled": False}}
194
+ results = self.checkContent(config, content)
195
+ self.assertEqual(len(results), 0)
196
+
197
+ # Rule explicitly enabled - should trigger error
198
+ config = {"TE04": {"enabled": True}}
199
+ results = self.checkContent(config, content)
200
+ self.assertEqual(len(results), 1)
201
+ self.assertTrue("TE04" in results[0])
202
+
203
+ def testTE05Disabled(self):
204
+ """Test that TE05 can be disabled with enabled: false"""
205
+ content = """
206
+ foo = bar...
207
+ """
208
+ # Rule enabled by default - should trigger error
209
+ results = self.checkContent({}, content)
210
+ self.assertEqual(len(results), 1)
211
+ self.assertTrue("TE05" in results[0])
212
+
213
+ # Rule explicitly disabled - should not trigger error
214
+ config = {"TE05": {"enabled": False}}
215
+ results = self.checkContent(config, content)
216
+ self.assertEqual(len(results), 0)
217
+
218
+ # Rule explicitly enabled - should trigger error
219
+ config = {"TE05": {"enabled": True}}
220
+ results = self.checkContent(config, content)
221
+ self.assertEqual(len(results), 1)
222
+ self.assertTrue("TE05" in results[0])
@@ -1 +0,0 @@
1
- version = "0.4.7"
@@ -1,112 +0,0 @@
1
- import unittest
2
- from src.fluent_linter import linter
3
- from fluent.syntax import parse
4
-
5
-
6
- class TestTypography(unittest.TestCase):
7
- def checkContent(self, config, content):
8
- l = linter.Linter(
9
- "path", "root", config, content, linter.get_offsets_and_lines(content)
10
- )
11
- l.visit(parse(content))
12
-
13
- return l.results
14
-
15
- def testTE01(self):
16
- content = """
17
- foo = bar's bar
18
- """
19
- results = self.checkContent({}, content)
20
- self.assertEqual(len(results), 1)
21
- self.assertTrue("TE01" in results[0])
22
- self.assertTrue("foo" in results[0])
23
-
24
- # Check exclusions
25
- config = {"TE01": {"exclusions": {"messages": ["foo"]}}}
26
- results = self.checkContent(config, content)
27
- self.assertEqual(len(results), 0)
28
-
29
- content = """
30
- foo = bar ' bar
31
- """
32
- results = self.checkContent({}, content)
33
- self.assertEqual(len(results), 0)
34
-
35
- def testTE02(self):
36
- content = """
37
- foo = bar‘s bar
38
- """
39
- results = self.checkContent({}, content)
40
- self.assertEqual(len(results), 1)
41
- self.assertTrue("TE02" in results[0])
42
- self.assertTrue("foo" in results[0])
43
-
44
- # Check exclusions
45
- config = {"TE02": {"exclusions": {"messages": ["foo"]}}}
46
- results = self.checkContent(config, content)
47
- self.assertEqual(len(results), 0)
48
-
49
- content = """
50
- foo = bar ‘ bar
51
- """
52
- results = self.checkContent({}, content)
53
- self.assertEqual(len(results), 0)
54
-
55
- def testTE03(self):
56
- content = """
57
- foo = bar 'bar' bar
58
- """
59
- results = self.checkContent({}, content)
60
- self.assertEqual(len(results), 2)
61
- self.assertTrue("TE01" in results[0])
62
- self.assertTrue("TE03" in results[1])
63
- self.assertTrue("foo" in results[0])
64
-
65
- # Check exclusions
66
- config = {
67
- "TE01": {"exclusions": {"messages": ["foo"]}},
68
- "TE03": {"exclusions": {"messages": ["foo"]}},
69
- }
70
- results = self.checkContent(config, content)
71
- self.assertEqual(len(results), 0)
72
-
73
- def testTE04(self):
74
- content = """
75
- foo = bar "bar" bar
76
- # This shouldn't trigger an error
77
- foo1 = { -someterm(capitalization: "uppercase") }
78
- foo-datetime = Test: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
79
- foo-number = { NUMBER($mem, maxFractionalUnits: 2) } MB
80
- foo-empty = { "" }
81
- foo-space = { "" } test
82
- foo-curly1 = { "{" } test
83
- foo-curly2 = { "}" } test
84
- """
85
- results = self.checkContent({}, content)
86
- self.assertEqual(len(results), 1)
87
- self.assertTrue("TE04" in results[0])
88
- self.assertTrue("foo" in results[0])
89
-
90
- # Check exclusions
91
- config = {"TE04": {"exclusions": {"messages": ["foo"]}}}
92
- results = self.checkContent(config, content)
93
- self.assertEqual(len(results), 0)
94
-
95
- def testTE05(self):
96
- content = """
97
- foo = bar...
98
- """
99
- results = self.checkContent({}, content)
100
- self.assertEqual(len(results), 1)
101
- self.assertTrue("TE05" in results[0])
102
-
103
- # Check exclusions
104
- config = {"TE05": {"exclusions": {"messages": ["foo"]}}}
105
- results = self.checkContent(config, content)
106
- self.assertEqual(len(results), 0)
107
-
108
- content = """
109
- foo = bar…
110
- """
111
- results = self.checkContent({}, content)
112
- self.assertEqual(len(results), 0)