Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
asdf | 7bd1974f0f | |
asdf | a1b660a7cd | |
asdf | 9ac11fa06e | |
asdf | d34aecb24d | |
asdf | a8ca9e98e5 | |
asdf | 8b6072c316 | |
asdf | aea4572121 | |
asdf | 33e8eca10c | |
asdf | 9aed41c8f7 | |
asdf | 1656c0fc7b | |
asdf | 8fe9af529b | |
asdf | e66d793646 |
46
data.py
46
data.py
|
@ -29,7 +29,7 @@ class LinkDataRecord(NamedTuple):
|
|||
def is_well_formed_line(line: str) -> bool:
|
||||
"""Checks if current line is valid or not, returns true or false respectively."""
|
||||
pipe_count = (
|
||||
4 ## A PROPERLY FORMATED LINE IN linkulator.data HAS EXACTLY FOUR PIPES.
|
||||
4 # A PROPERLY FORMATED LINE IN linkulator.data HAS EXACTLY FOUR PIPES.
|
||||
)
|
||||
return line.count("|") == pipe_count
|
||||
|
||||
|
@ -139,9 +139,9 @@ class LinkData:
|
|||
"""sort link_data by creation date"""
|
||||
self.link_data.sort(key=lambda x: x[2], reverse=True)
|
||||
|
||||
def add(self, record) -> int:
|
||||
def add(self, record):
|
||||
"""Add a record to the data file, and to link_data. Returns a new post
|
||||
ID, if record is a post, or -1"""
|
||||
ID, if record is a post, or None"""
|
||||
if os.path.exists(config.USER.datafile):
|
||||
append_write = "a" # append if already exists
|
||||
else:
|
||||
|
@ -157,7 +157,7 @@ class LinkData:
|
|||
)
|
||||
)
|
||||
|
||||
new_post_id = -1
|
||||
new_post_id = None
|
||||
if record.category:
|
||||
if self.link_data:
|
||||
new_post_id = (
|
||||
|
@ -175,6 +175,7 @@ class LinkData:
|
|||
|
||||
def generate_category_data(self):
|
||||
"""generate categories list and category count from sorted link data"""
|
||||
# TODO: add unread status bool to this query's results
|
||||
self.categories.clear()
|
||||
for record in self.link_data:
|
||||
name = record[4]
|
||||
|
@ -238,14 +239,16 @@ class LinkData:
|
|||
|
||||
return sorted(search_results, key=lambda x: x[0], reverse=True)
|
||||
|
||||
def list_category_details(self, selected_category: str) -> list:
|
||||
"""returns a sorted list of posts belonging to the specified category"""
|
||||
def get_links_by_category_name(self, category_name: str) -> list:
|
||||
"""accepts a category name. returns a sorted list of posts belonging to
|
||||
the specified category"""
|
||||
|
||||
links = []
|
||||
|
||||
for record in self.link_data:
|
||||
category = record[4]
|
||||
if category == selected_category:
|
||||
postid = record[0]
|
||||
if category == category_name:
|
||||
post_id = record[0]
|
||||
userid = record[1]
|
||||
timestamp = record[2]
|
||||
parent_id = userid + "+" + str(timestamp)
|
||||
|
@ -269,7 +272,7 @@ class LinkData:
|
|||
|
||||
links.append(
|
||||
{
|
||||
"postid": postid,
|
||||
"post_id": post_id,
|
||||
"link_timestamp": timestamp,
|
||||
"link_author": userid,
|
||||
"reply_count": len(replies),
|
||||
|
@ -278,5 +281,28 @@ class LinkData:
|
|||
"last_modified_timestamp": last_modified_timestamp,
|
||||
}
|
||||
)
|
||||
links.sort(key=lambda x: x["last_modified_timestamp"], reverse=True)
|
||||
return links
|
||||
|
||||
return sorted(links, key=lambda x: x["last_modified_timestamp"], reverse=True)
|
||||
def get_post(self, post_id) -> dict:
|
||||
output = {}
|
||||
for record in self.link_data:
|
||||
if record[0] == post_id:
|
||||
output["parent_id"] = "{}+{}".format(record[1], str(record[2]))
|
||||
output["author"] = record[1]
|
||||
output["timestamp"] = record[2]
|
||||
output["category"] = record[4]
|
||||
output["url"] = record[5]
|
||||
output["title"] = record[6]
|
||||
break
|
||||
|
||||
if not output["parent_id"]:
|
||||
raise ValueError("Sorry, no thread found with that ID.")
|
||||
|
||||
# TODO: this should return just the required fields
|
||||
output["replies"] = sorted(
|
||||
[record for record in self.link_data if record[3] == output["parent_id"]],
|
||||
key=lambda x: x[2],
|
||||
)
|
||||
|
||||
return output
|
||||
|
|
1070
linkulator.py
1070
linkulator.py
File diff suppressed because it is too large
Load Diff
|
@ -25,7 +25,7 @@ class TestDataHelperFunctions(unittest.TestCase):
|
|||
self.assertEqual(data.wash_line(line["Test"]), line["Result"])
|
||||
|
||||
def test_is_well_formed_line(self):
|
||||
""" tests the data.is_well_formed_line function"""
|
||||
"""tests the data.is_well_formed_line function"""
|
||||
teststrings = [
|
||||
{"Test": "A line of text", "Result": False},
|
||||
{"Test": "1 Pipe |", "Result": False},
|
||||
|
|
|
@ -2,38 +2,237 @@
|
|||
"""Tests for Linkulator views"""
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch, call
|
||||
import linkulator
|
||||
|
||||
# TODO: update to support list of strings output
|
||||
# class TestViewSearchResults(unittest.TestCase):
|
||||
# """Tests covering the view_search_results function"""
|
||||
|
||||
class TestPrintSearchResults(unittest.TestCase):
|
||||
"""Tests covering the print_search_results function"""
|
||||
# @patch("builtins.print")
|
||||
# def test_print_search_results(self, mock_print):
|
||||
# """tests that the search results are produced correctly"""
|
||||
# test_keyword = "keyword"
|
||||
# test_search_results = [
|
||||
# (66, "keyword", "1576461366.5580268", "", "c", "c", "c"),
|
||||
# (65, "poster6", "1576461367.5580268", "", "keyword", "c", "c"),
|
||||
# (64, "poster7", "1576461368.5580268", "", "c", "keyword", "c"),
|
||||
# (63, "poster8", "1576461369.5580268", "", "c", "c", "keyword"),
|
||||
# ]
|
||||
# expected_output = [
|
||||
# call(
|
||||
# "\nShowing results for keyword\n\n ID# DATE AUTHOR DESC "
|
||||
# ),
|
||||
# call(" 1 2019-12-16 keyword c "),
|
||||
# call(" 2 2019-12-16 poster6 c "),
|
||||
# call(" 3 2019-12-16 poster7 c "),
|
||||
# call(" 4 2019-12-16 poster8 keyword "),
|
||||
# call(""),
|
||||
# ]
|
||||
#
|
||||
# linkulator.view_search_results(test_keyword, test_search_results)
|
||||
#
|
||||
# self.assertEqual(
|
||||
# mock_print.call_count, 6
|
||||
# ) # one count for title, 4 for the items and a blank line for formatting
|
||||
#
|
||||
# self.assertListEqual(test_view_calls, mock_print.call_args_list)
|
||||
|
||||
@patch("builtins.print")
|
||||
def test_print_search_results(self, mock_print):
|
||||
"""tests that the search results are printed correctly"""
|
||||
test_keyword = "keyword"
|
||||
test_search_results = [
|
||||
(66, "keyword", "1576461366.5580268", "", "c", "c", "c"),
|
||||
(65, "poster6", "1576461367.5580268", "", "keyword", "c", "c"),
|
||||
(64, "poster7", "1576461368.5580268", "", "c", "keyword", "c"),
|
||||
(63, "poster8", "1576461369.5580268", "", "c", "c", "keyword"),
|
||||
|
||||
class TestViewCategories(unittest.TestCase):
|
||||
def test_view_categories(self):
|
||||
"""Test general output of view_categories"""
|
||||
|
||||
categories = [
|
||||
{
|
||||
"name": "category 1",
|
||||
"count": 1,
|
||||
"last_updated": "10",
|
||||
},
|
||||
{
|
||||
"name": "category 2",
|
||||
"count": 2,
|
||||
"last_updated": "100",
|
||||
},
|
||||
{
|
||||
"name": "long category name that will be truncated because it's a long line, longer than the terminal width. that's for sure.",
|
||||
"count": 20,
|
||||
"last_updated": "1000",
|
||||
},
|
||||
]
|
||||
test_print_calls = [
|
||||
call(
|
||||
"\nShowing results for keyword\n\n ID# DATE AUTHOR DESC "
|
||||
),
|
||||
call(" 1 2019-12-16 keyword c "),
|
||||
call(" 2 2019-12-16 poster6 c "),
|
||||
call(" 3 2019-12-16 poster7 c "),
|
||||
call(" 4 2019-12-16 poster8 keyword "),
|
||||
call(""),
|
||||
cols = 80
|
||||
|
||||
expected_header = " ID# New Category"
|
||||
|
||||
expected_content = [
|
||||
" 1 * category 1 (1)",
|
||||
" 2 * category 2 (2)",
|
||||
" 3 * long category name that will be truncated because it's a long... (20)",
|
||||
]
|
||||
|
||||
linkulator.print_search_results(test_keyword, test_search_results)
|
||||
actual_header, actual_content = linkulator.view_categories(categories, cols)
|
||||
|
||||
self.assertEqual(
|
||||
mock_print.call_count, 6
|
||||
) # one count for title, 4 for the items and a blank line for formatting
|
||||
# confirm expected is equal to actual
|
||||
self.assertEqual(expected_header, actual_header)
|
||||
self.assertListEqual(expected_content, actual_content)
|
||||
|
||||
self.assertListEqual(test_print_calls, mock_print.call_args_list)
|
||||
# confirm actual does not exceed cols
|
||||
header_max_cols = max([len(line) for line in actual_header])
|
||||
self.assertTrue(header_max_cols <= cols)
|
||||
content_max_cols = max([len(line) for line in actual_content])
|
||||
self.assertTrue(content_max_cols <= cols)
|
||||
|
||||
def test_empty_categories(self):
|
||||
"""Test output when no categories data"""
|
||||
empty_categories = []
|
||||
cols = 80
|
||||
expected_header = ""
|
||||
expected_content = [
|
||||
"",
|
||||
"There are no posts yet - enter p to post a new link",
|
||||
]
|
||||
actual_header, actual_content = linkulator.view_categories(
|
||||
empty_categories, cols
|
||||
)
|
||||
|
||||
# confirm expected is equal to actual
|
||||
self.assertEqual(expected_header, actual_header)
|
||||
self.assertListEqual(expected_content, actual_content)
|
||||
|
||||
# confirm actual does not exceed cols
|
||||
content_max_cols = max([len(line) for line in actual_content])
|
||||
self.assertTrue(content_max_cols <= cols)
|
||||
|
||||
|
||||
class TestViewLinks(unittest.TestCase):
|
||||
def test_view_links(self):
|
||||
"""Test general output of view_links"""
|
||||
|
||||
links = [
|
||||
{
|
||||
"post_id": 1,
|
||||
"link_timestamp": "1627549445.044661",
|
||||
"link_author": "auth 1",
|
||||
"reply_count": 0,
|
||||
"description": "description 1",
|
||||
"has_new_replies": False,
|
||||
"last_modified_timestamp": "1627549445.044661",
|
||||
},
|
||||
{
|
||||
"post_id": 2,
|
||||
"link_timestamp": "1627549445.044661",
|
||||
"link_author": "author 2 with a long name",
|
||||
"reply_count": 250,
|
||||
"description": "a long description for the second post that should wrap i guess",
|
||||
"has_new_replies": True,
|
||||
"last_modified_timestamp": "1627549445.044661",
|
||||
},
|
||||
]
|
||||
|
||||
cols = 80
|
||||
category_name = "Test Name"
|
||||
expected_header = " Test Name\n ID# Date Author #Repl Description"
|
||||
expected_content = [
|
||||
" 1 2021-07-29 auth 1 [ 0] description 1",
|
||||
" 2 2021-07-29 author 2 [ 25] a long description for the second post...*",
|
||||
]
|
||||
|
||||
actual_header, actual_content = linkulator.view_links(
|
||||
links, category_name, cols
|
||||
)
|
||||
|
||||
# confirm expected is equal to actual
|
||||
self.assertEqual(expected_header, actual_header)
|
||||
self.assertListEqual(expected_content, actual_content)
|
||||
|
||||
# confirm actual does not exceed cols
|
||||
header_max_cols = max([len(line) for line in actual_header])
|
||||
self.assertTrue(header_max_cols <= cols)
|
||||
content_max_cols = max([len(line) for line in actual_content])
|
||||
self.assertTrue(content_max_cols <= cols)
|
||||
|
||||
|
||||
class TestViewPost(unittest.TestCase):
|
||||
def test_post_without_reply(self):
|
||||
"""Test view_post where the post has no reply"""
|
||||
|
||||
post = {
|
||||
"author": "post author 1",
|
||||
"category": "test category 1",
|
||||
"timestamp": "100",
|
||||
"parent_id": "author+timestamp",
|
||||
"replies": [],
|
||||
"title": "A cool website",
|
||||
"url": "http://asdflkjasdf",
|
||||
}
|
||||
|
||||
cols = 80
|
||||
expected_content = [
|
||||
" Title : A cool website",
|
||||
" Link : http://asdflkjasdf",
|
||||
" Category : test category 1",
|
||||
" User : post author 1",
|
||||
" Date : Thu 01 Jan 1970 10:01:40",
|
||||
"\n No replies yet. Be the first!",
|
||||
]
|
||||
|
||||
actual_content = linkulator.view_post(post, cols)
|
||||
|
||||
# confirm expected is equal to actual
|
||||
self.assertListEqual(actual_content, expected_content)
|
||||
|
||||
# confirm actual does not exceed cols
|
||||
content_max_cols = max([len(line) for line in actual_content])
|
||||
self.assertTrue(content_max_cols <= cols)
|
||||
|
||||
def test_post_with_reply(self):
|
||||
"""Test view_post where the post has a reply"""
|
||||
|
||||
post = {
|
||||
"author": "author2",
|
||||
"category": "category 2",
|
||||
"timestamp": "1000",
|
||||
"parent_id": "xxxxxxxxx",
|
||||
"replies": [
|
||||
[
|
||||
"",
|
||||
"reply author 1",
|
||||
"1001",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"a reply",
|
||||
],
|
||||
[
|
||||
"",
|
||||
"reply author 2 with a long long long name, a very long name",
|
||||
"1002",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"a reply with a lot of words in it, too many to read, not going to read this",
|
||||
],
|
||||
],
|
||||
"title": "Website 2",
|
||||
"url": "asdflkjasdf",
|
||||
}
|
||||
|
||||
cols = 80
|
||||
expected_content = [
|
||||
" Title : Website 2",
|
||||
" Link : asdflkjasdf",
|
||||
" Category : category 2",
|
||||
" User : author2",
|
||||
" Date : Thu 01 Jan 1970 10:16:40",
|
||||
"\n Replies:\n",
|
||||
" 1970-01-01 10:16 reply author 1: a reply",
|
||||
" 1970-01-01 10:16 reply author 2 with a long long long name, a very long name: a reply with a lot of words in it, too many to read, not going to read this",
|
||||
]
|
||||
|
||||
actual_content = linkulator.view_post(post, cols)
|
||||
|
||||
# confirm expected is equal to actual
|
||||
self.assertListEqual(actual_content, expected_content)
|
||||
|
||||
# confirm actual does not exceed cols
|
||||
content_max_cols = max([len(line) for line in actual_content])
|
||||
self.assertTrue(content_max_cols <= cols)
|
||||
|
|
Loading…
Reference in New Issue