Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don’t worry, you can still create the pull request.
  • 10 commits
  • 3 files changed
  • 1 commit comment
  • 1 contributor
Commits on Apr 02, 2012
@nandhp nandhp Support autolinking to timereddits, /r/t:when (1 April 2012) 97aa8d4
@nandhp nandhp Avoid extra isalnum check for timereddit autolinking. aeeca17
Commits on Apr 03, 2012
@nandhp nandhp Don't autolink subreddits with names that are shorter than three char…
…acters.

One or two character subreddit names are invalid, so linking to them makes no
sense. This also avoids funny behavior with autolinking /r/t, due to the new
autolinking support for timereddits.
fc0d792
@nandhp nandhp Add support for autolinking /r/reddit.com and fix links to multireddits.
Multireddit linking didn't support reddit.com or timereddits because
'+' was treated like a standard character, and would not recheck for
special subreddits. So now /r/abc+t:def+reddit.com works.
e526662
@nandhp nandhp Add unit test for subreddit and username autolinking.
I'm not sure how to Pythonically integrate this into the distribution.
68e0e4e
Commits on Apr 19, 2012
@nandhp nandhp Actually, some two-character subreddits (e.g. /r/ca) exist. 4163072
@nandhp nandhp More test cases for two-character subreddits 09a9e85
@nandhp nandhp More exhaustive list of prefixes and suffixes for autolinking test f89e537
@nandhp nandhp Update subreddit autolinking to support two-character subreddit names 1244c5c
@nandhp nandhp Merge branch 'master' into unittest b76e101
Showing with 134 additions and 11 deletions.
  1. +39 −1 setup.py
  2. +57 −0 snudown_tests.py
  3. +38 −10 src/autolink.c
View
40 setup.py
@@ -1,4 +1,6 @@
-from distutils.core import setup, Extension
+from distutils.core import setup, Extension, Command
+
+import unittest, sys
import os
import fnmatch
@@ -10,6 +12,41 @@ def c_files_in(directory):
paths.append(os.path.join(directory, f))
return paths
+class RunTests(Command):
+ user_options = []
+ def initialize_options(self):
+ pass
+ def finalize_options(self):
+ pass
+
+ # From disttest, copyright (c) 2010 Jared Forsyth, MIT license
+ # https://github.com/jabapyth/disttest/blob/master/disttest.py
+ def with_project_on_sys_path(self, func):
+ self.run_command('build')
+ cmd = self.get_finalized_command('build_py')
+
+ old_path = sys.path[:]
+ old_modules = sys.modules.copy()
+
+ from os.path import normpath as normalize_path
+
+ try:
+ sys.path.insert(0, normalize_path(cmd.build_lib))
+ func()
+ finally:
+ sys.path[:] = old_path
+ sys.modules.clear()
+ sys.modules.update(old_modules)
+
+ def run(self):
+ self.with_project_on_sys_path(self.run_tests)
+
+ def run_tests(self):
+ import snudown_tests
+ suite = unittest.TestLoader().loadTestsFromModule(snudown_tests)
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ sys.exit(0 if result.wasSuccessful() else 1)
+
setup(
name='snudown',
version='1.0.5',
@@ -23,4 +60,5 @@ def c_files_in(directory):
include_dirs=['src', 'html']
)
],
+ cmdclass = {'test': RunTests},
)
View
57 snudown_tests.py
@@ -0,0 +1,57 @@
+import snudown
+import unittest
+
+class SnudownTest(unittest.TestCase):
+ testdata = {}
+ def runTest(self):
+ for md,html in self.testdata:
+ self.assertEqual(snudown.markdown(md), html)
+
+class TestSubredditAndUsernameAutolinking(SnudownTest):
+ testdata = []
+
+ def __init__(self, methodName='runTest'):
+ SnudownTest.__init__(self, methodName)
+
+ # These strings will be autolinked
+ ok = [
+ # Subreddits
+ '/r/ca', '/r/abc', '/r/t:y', '/r/reddit.com', '/r/1984sweet1984',
+ '/r/fffffffuuuuuuuuuuuu01',
+ '/r/funny+pics', '/r/reddit.com+funny+AskReddit',
+ '/r/t:yesterday+t:tommorow', '/r/reddit.com+funny+t:tommorow',
+ '/r/t:tommorow+funny+reddit.com',
+ '/r/t:now+ca+funny', '/r/funny+ca', '/r/ca+funny',
+ # Usernames
+ '/u/abc', '/u/_username'
+ ]
+ # These strings will not be autolinked
+ notok = [
+ # Subreddits
+ '/r/', '/r/!',
+ '/r/a', '/r/t', '/r/t', '/r/t:', '/r/a:', '/r/a:b',
+ '/r/a:bcd',
+ '/r/reddit.comx',
+ '/r/fffffffuuuuuuuuuuuu012',
+ '/r/funny+reddit.comx+abc', '/r/funny+r:ome',
+ '/r/foo+', '/r/+foo', '/r/foo++bar',
+ '/r/t+ca', '/r/ca+t', '/r/t:+foo',
+ # Usernames
+ '/u/', '/u/!'
+ ]
+
+ # Generate the test list using various prefixes and suffixes
+ prefix_and_suffix_list = (
+ ('',''),('abc',' def'),('abc ',' def'),
+ ('abc ',', def'), ('abc ',': def'), ('abc ','!'),
+ )
+ for x in ok:
+ xl = '<a href="' + x + '">' + x + '</a>'
+ for pre,suf in prefix_and_suffix_list:
+ self.testdata.append((pre+x+suf, '<p>'+pre+xl+suf+'</p>\n'))
+ for x in notok:
+ for pre,suf in prefix_and_suffix_list:
+ self.testdata.append((pre+x+suf, '<p>'+pre+x+suf+'</p>\n'))
+
+if __name__ == '__main__':
+ unittest.main()
View
48 src/autolink.c
@@ -271,18 +271,46 @@ sd_autolink__subreddit(size_t *rewind_p, struct buf *link, uint8_t *data, size_t
/* make sure this / is part of /r/ */
if (strncasecmp((char*)data, "/r/", 3) != 0)
return 0;
-
- /* the first character of a subreddit name must be a letter or digit */
link_end = strlen("/r/");
- if (!isalnum(data[link_end]))
- return 0;
- link_end += 1;
- /* consume valid characters ([A-Za-z0-9_]) until we run out */
- while (link_end < size && (isalnum(data[link_end]) ||
- data[link_end] == '_' ||
- data[link_end] == '+'))
- link_end++;
+ do {
+ size_t start = link_end;
+ int max_length = 21;
+
+ /* special case: /r/reddit.com (only subreddit containing '.'). */
+ if ( size >= link_end+10 && strncasecmp((char*)data+link_end, "reddit.com", 10) == 0 ) {
+ link_end += 10;
+ /* Make sure there are no trailing characters (don't do
+ * any autolinking for /r/reddit.commission) */
+ max_length = 10;
+ }
+
+ /* If not a special case, verify it begins with (t:)?[A-Za-z0-9] */
+ else {
+ /* support autolinking to timereddits, /r/t:when (1 April 2012) */
+ if ( size > link_end+2 && strncasecmp((char*)data+link_end, "t:", 2) == 0 )
+ link_end += 2; /* Jump over the 't:' */
+
+ /* the first character of a subreddit name must be a letter or digit */
+ if (!isalnum(data[link_end]))
+ return 0;
+ link_end += 1;
+ }
+
+ /* consume valid characters ([A-Za-z0-9_]) until we run out */
+ while (link_end < size && (isalnum(data[link_end]) ||
+ data[link_end] == '_'))
+ link_end++;
+
+ /* valid subreddit names are between 3 and 21 characters, with
+ * some subreddits having 2-character names. Don't bother with
+ * autolinking for anything outside this length range.
+ * (chksrname function in reddit/.../validator.py) */
+ if ( link_end-start < 2 || link_end-start > max_length )
+ return 0;
+
+ /* If we are linking to a multireddit, continue */
+ } while ( link_end < size && data[link_end] == '+' && link_end++ );
/* make the link */
bufput(link, data, link_end);

Showing you all comments on commits in this comparison.

@spladug
Owner

Could you move this up to line 277 or so, so that we don't have to duplicate the isalnum check? It may also be worthwhile to check that we're not going outside the bounds of the string.

Something went wrong with that request. Please try again.