unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* WIP: add a (count ...) modifier for sexp-queries
@ 2023-02-18 17:17 David Bremner
  2023-02-18 17:17 ` [PATCH 1/6] WIP/lib: add count query backend David Bremner
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

This updates and obsoletes the series at [1]. The backend that
constructs queries is unmodified from that series, but the parser now
allows the use of count modifier in several more places. Basically
there is not much more code to maintain to do it for any field based
on terms (notably not date), but the utility is a bit unclear in some
cases.

In (probably) decreasing order of compelling use case

1) (and (from bob) (thread (count 1))) # find messages from bob nobody replied to yet.

2) (and (subject init-systems) (thread (count 200 *))) # find me a mega thread on some topic

3) (and (to bremner) (from (count (2 *))))  # find people that sent me at least 2 messages.

4) (tag (count 1)) # find tags used only once 
   
5) (path (count 1)) # find messages alone in a directory

6) (subject (count 1)) # find words used only once in subjects

[1]: id:20230213122631.2088558-1-david@tethera.net


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/6] WIP/lib: add count query backend
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
@ 2023-02-18 17:17 ` David Bremner
  2023-02-18 17:17 ` [PATCH 2/6] WIP/lib: support count modifier in sexp queries David Bremner
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

---
 lib/Makefile.local     |  3 +-
 lib/count-query.cc     | 62 ++++++++++++++++++++++++++++++++++++++++++
 lib/database-private.h |  6 ++++
 3 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 lib/count-query.cc

diff --git a/lib/Makefile.local b/lib/Makefile.local
index 4e766305..cc646946 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -66,7 +66,8 @@ libnotmuch_cxx_srcs =		\
 	$(dir)/init.cc		\
 	$(dir)/parse-sexp.cc	\
 	$(dir)/sexp-fp.cc	\
-	$(dir)/lastmod-fp.cc
+	$(dir)/lastmod-fp.cc    \
+	$(dir)/count-query.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
 
diff --git a/lib/count-query.cc b/lib/count-query.cc
new file mode 100644
index 00000000..5d258880
--- /dev/null
+++ b/lib/count-query.cc
@@ -0,0 +1,62 @@
+/* count-query.cc - generate queries for terms on few / many messages.
+ *
+ * This file is part of notmuch.
+ *
+ * Copyright © 2023 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#include "database-private.h"
+
+notmuch_status_t
+_notmuch_count_strings_to_query (notmuch_database_t *notmuch, std::string field,
+				 const std::string &from, const std::string &to,
+				 Xapian::Query &output, std::string &msg)
+{
+
+    long from_idx = 0, to_idx = LONG_MAX;
+    std::string term_prefix = _find_prefix (field.c_str ());
+    std::vector<std::string> terms;
+
+    if (! from.empty ()) {
+	try {
+	    from_idx = std::stol(from);
+	} catch (std::logic_error &e) {
+	    msg = "bad 'from' count: '" + from + "'";
+	    return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+	}
+    }
+
+    if (! to.empty ()) {
+	try {
+	    to_idx = std::stod(to);
+	} catch (std::logic_error &e) {
+	    msg = "bad 'to' count: '" + to + "'";
+	    return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+	}
+    }
+
+    for (Xapian::TermIterator it = notmuch->xapian_db->allterms_begin (term_prefix);
+	 it != notmuch->xapian_db->allterms_end (); ++it) {
+	Xapian::doccount freq = it.get_termfreq();
+	if (from_idx <= freq && freq <= to_idx)
+	    terms.push_back (*it);
+    }
+
+    output = Xapian::Query (Xapian::Query::OP_OR, terms.begin (), terms.end ());
+    return NOTMUCH_STATUS_SUCCESS;
+}
diff --git a/lib/database-private.h b/lib/database-private.h
index b9be4e22..ba96a93c 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -387,5 +387,11 @@ notmuch_status_t
 _notmuch_lastmod_strings_to_query (notmuch_database_t *notmuch,
 				   const std::string &from, const std::string &to,
 				   Xapian::Query &output, std::string &msg);
+
+/* count-query.cc */
+notmuch_status_t
+_notmuch_count_strings_to_query (notmuch_database_t *notmuch, std::string field,
+				 const std::string &from, const std::string &to,
+				 Xapian::Query &output, std::string &msg);
 #endif
 #endif
-- 
2.39.1
\r

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/6] WIP/lib: support count modifier in sexp queries
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
  2023-02-18 17:17 ` [PATCH 1/6] WIP/lib: add count query backend David Bremner
@ 2023-02-18 17:17 ` David Bremner
  2023-02-18 17:17 ` [PATCH 3/6] WIP/test: (count ...) tests for to / from David Bremner
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

In this initial commit, support all term based fields, but only
document/test the thread size feature.
---
 lib/parse-sexp.cc        | 65 ++++++++++++++++++++++++++++++----------
 test/T083-sexpr-count.sh | 30 +++++++++++++++++++
 2 files changed, 79 insertions(+), 16 deletions(-)
 create mode 100755 test/T083-sexpr-count.sh

diff --git a/lib/parse-sexp.cc b/lib/parse-sexp.cc
index 9cadbc13..efe564c7 100644
--- a/lib/parse-sexp.cc
+++ b/lib/parse-sexp.cc
@@ -34,6 +34,8 @@ typedef enum {
     SEXP_FLAG_ORPHAN	= 1 << 8,
     SEXP_FLAG_RANGE	= 1 << 9,
     SEXP_FLAG_PATHNAME	= 1 << 10,
+    SEXP_FLAG_COUNT	= 1 << 11,
+    SEXP_FLAG_MODIFIER	= 1 << 12,
 } _sexp_flag_t;
 
 /*
@@ -65,24 +67,28 @@ static _sexp_prefix_t prefixes[] =
     { "and",            Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
       SEXP_FLAG_NONE },
     { "attachment",     Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_EXPAND | SEXP_FLAG_COUNT},
     { "body",           Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
       SEXP_FLAG_FIELD },
     { "date",           Xapian::Query::OP_INVALID,      Xapian::Query::MatchAll,
-      SEXP_FLAG_RANGE },
+      SEXP_FLAG_FIELD | SEXP_FLAG_RANGE },
+    { "count",          Xapian::Query::OP_INVALID,      Xapian::Query::MatchAll,
+      SEXP_FLAG_MODIFIER | SEXP_FLAG_RANGE },
     { "from",           Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND
+      | SEXP_FLAG_COUNT },
     { "folder",         Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
-      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND |
-      SEXP_FLAG_PATHNAME },
+      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX
+      | SEXP_FLAG_EXPAND | SEXP_FLAG_PATHNAME | SEXP_FLAG_COUNT },
     { "id",             Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
       SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX },
     { "infix",          Xapian::Query::OP_INVALID,      Xapian::Query::MatchAll,
       SEXP_FLAG_SINGLE | SEXP_FLAG_ORPHAN },
     { "is",             Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD |
+      SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND  | SEXP_FLAG_COUNT },
     { "lastmod",           Xapian::Query::OP_INVALID,      Xapian::Query::MatchAll,
-      SEXP_FLAG_RANGE },
+      SEXP_FLAG_FIELD | SEXP_FLAG_RANGE },
     { "matching",       Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
       SEXP_FLAG_DO_EXPAND },
     { "mid",            Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
@@ -97,9 +103,10 @@ static _sexp_prefix_t prefixes[] =
       SEXP_FLAG_NONE },
     { "path",           Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
       SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX |
-      SEXP_FLAG_PATHNAME },
+      SEXP_FLAG_PATHNAME | SEXP_FLAG_COUNT},
     { "property",       Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD |
+      SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND | SEXP_FLAG_COUNT },
     { "query",          Xapian::Query::OP_INVALID,      Xapian::Query::MatchNothing,
       SEXP_FLAG_SINGLE | SEXP_FLAG_ORPHAN },
     { "regex",          Xapian::Query::OP_INVALID,      Xapian::Query::MatchAll,
@@ -109,13 +116,16 @@ static _sexp_prefix_t prefixes[] =
     { "starts-with",    Xapian::Query::OP_WILDCARD,     Xapian::Query::MatchAll,
       SEXP_FLAG_SINGLE },
     { "subject",        Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND
+      | SEXP_FLAG_COUNT },
     { "tag",            Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX
+      | SEXP_FLAG_EXPAND | SEXP_FLAG_COUNT},
     { "thread",         Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
-      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX |
+      SEXP_FLAG_EXPAND | SEXP_FLAG_COUNT },
     { "to",             Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
-      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_EXPAND },
+      SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_EXPAND | SEXP_FLAG_COUNT },
     { }
 };
 
@@ -513,6 +523,7 @@ _sexp_expand_param (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
 
 static notmuch_status_t
 _sexp_parse_range (notmuch_database_t *notmuch,  const _sexp_prefix_t *prefix,
+		   const _sexp_prefix_t *parent,
 		   const sexp_t *sx, Xapian::Query &output)
 {
     const char *from, *to;
@@ -552,6 +563,27 @@ _sexp_parse_range (notmuch_database_t *notmuch,  const _sexp_prefix_t *prefix,
 	    to = "";
     }
 
+    if (strcmp (prefix->name, "count") == 0) {
+	notmuch_status_t status;
+	if (! parent) {
+	    _notmuch_database_log (notmuch, "illegal '%s' outside field\n",
+				   prefix->name);
+	    return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+	}
+	if (! (parent->flags & SEXP_FLAG_COUNT)) {
+	    _notmuch_database_log (notmuch, "'%s' not supported in field '%s'\n",
+				   prefix->name, parent->name);
+	    return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+	}
+
+	status = _notmuch_count_strings_to_query (notmuch, parent->name, from, to, output, msg);
+	if (status) {
+	    if (! msg.empty ())
+		_notmuch_database_log (notmuch, "%s\n", msg.c_str ());
+	}
+	return status;
+    }
+
     if (strcmp (prefix->name, "date") == 0) {
 	notmuch_status_t status;
 	status = _notmuch_date_strings_to_query (NOTMUCH_VALUE_TIMESTAMP, from, to, output, msg);
@@ -612,7 +644,8 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
 	} else {
 	    Xapian::Query accumulator;
 	    for (_sexp_prefix_t *prefix = prefixes; prefix->name; prefix++) {
-		if (prefix->flags & SEXP_FLAG_FIELD) {
+		if (prefix->flags & SEXP_FLAG_FIELD &&
+		    !(prefix->flags & SEXP_FLAG_RANGE)) {
 		    Xapian::Query subquery;
 		    term_prefix = _notmuch_database_prefix (notmuch, prefix->name);
 		    status = _sexp_parse_one_term (notmuch, term_prefix, sx, subquery);
@@ -654,7 +687,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
 
     for (_sexp_prefix_t *prefix = prefixes; prefix && prefix->name; prefix++) {
 	if (strcmp (prefix->name, sx->list->val) == 0) {
-	    if (prefix->flags & (SEXP_FLAG_FIELD | SEXP_FLAG_RANGE)) {
+	    if (prefix->flags & SEXP_FLAG_FIELD) {
 		if (parent) {
 		    _notmuch_database_log (notmuch, "nested field: '%s' inside '%s'\n",
 					   prefix->name, parent->name);
@@ -677,7 +710,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
 	    }
 
 	    if (prefix->flags & SEXP_FLAG_RANGE)
-		return _sexp_parse_range (notmuch, prefix, sx->list->next, output);
+		return _sexp_parse_range (notmuch, prefix, parent, sx->list->next, output);
 
 	    if (strcmp (prefix->name, "infix") == 0) {
 		return _sexp_parse_infix (notmuch, sx->list->next, output);
diff --git a/test/T083-sexpr-count.sh b/test/T083-sexpr-count.sh
new file mode 100755
index 00000000..e825ef3d
--- /dev/null
+++ b/test/T083-sexpr-count.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+test_description='"(count ...)" modifier for sexp queries'
+. $(dirname "$0")/test-lib.sh || exit 1
+
+if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
+    printf "Skipping due to missing sfsexp library\n"
+    test_done
+fi
+
+add_email_corpus
+
+test_begin_subtest "threads with one message"
+notmuch search --query=sexp '(and (from gusarov) (thread (count 1)))' | notmuch_search_sanitize > OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX   2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "partition threads by size"
+notmuch count --output=threads --query=sexp '()' > OUTPUT
+notmuch count --output=threads --query=sexp '(thread (count 1 2))' >> OUTPUT
+notmuch count --output=threads --query=sexp '(thread (count 3 *))' >> OUTPUT
+cat <<EOF >EXPECTED
+24
+16
+8
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
-- 
2.39.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/6] WIP/test: (count ...) tests for to / from
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
  2023-02-18 17:17 ` [PATCH 1/6] WIP/lib: add count query backend David Bremner
  2023-02-18 17:17 ` [PATCH 2/6] WIP/lib: support count modifier in sexp queries David Bremner
@ 2023-02-18 17:17 ` David Bremner
  2023-02-18 17:17 ` [PATCH 4/6] WIP/test: pathname related tests David Bremner
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

---
 test/T083-sexpr-count.sh | 85 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/test/T083-sexpr-count.sh b/test/T083-sexpr-count.sh
index e825ef3d..f3010d11 100755
--- a/test/T083-sexpr-count.sh
+++ b/test/T083-sexpr-count.sh
@@ -27,4 +27,89 @@ cat <<EOF >EXPECTED
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "from addresses with any count"
+notmuch address --query=sexp '(from (count 1 *))' | sort > OUTPUT
+cat <<EOF >EXPECTED
+Adrian Perez de Castro <aperez@igalia.com>
+Alex Botero-Lowry <alex.boterolowry@gmail.com>
+Alexander Botero-Lowry <alex.boterolowry@gmail.com>
+Aron Griffis <agriffis@n01se.net>
+Carl Worth <cworth@cworth.org>
+Chris Wilson <chris@chris-wilson.co.uk>
+François Boulogne <boulogne.f@gmail.com>
+Ingmar Vanhassel <ingmar@exherbo.org>
+Israel Herraiz <isra@herraiz.org>
+Jan Janak <jan@ryngle.com>
+Jjgod Jiang <gzjjgod@gmail.com>
+Keith Packard <keithp@keithp.com>
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Mikhail Gusarov <dottedmag@dottedmag.net>
+Olivier Berger <olivier.berger@it-sudparis.eu>
+Rolland Santimano <rollandsantimano@yahoo.com>
+Stewart Smith <stewart@flamingspork.com>
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "from addresses with unique words"
+notmuch address --query=sexp '(from (count 1))' | sort > OUTPUT
+cat <<EOF >EXPECTED
+Adrian Perez de Castro <aperez@igalia.com>
+Aron Griffis <agriffis@n01se.net>
+Chris Wilson <chris@chris-wilson.co.uk>
+François Boulogne <boulogne.f@gmail.com>
+Ingmar Vanhassel <ingmar@exherbo.org>
+Israel Herraiz <isra@herraiz.org>
+Olivier Berger <olivier.berger@it-sudparis.eu>
+Rolland Santimano <rollandsantimano@yahoo.com>
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "from addresses with only non-unique words"
+notmuch address --query=sexp '(from (not (count 1)))' | sort > OUTPUT
+cat <<EOF >EXPECTED
+Alex Botero-Lowry <alex.boterolowry@gmail.com>
+Alexander Botero-Lowry <alex.boterolowry@gmail.com>
+Carl Worth <cworth@cworth.org>
+Jan Janak <jan@ryngle.com>
+Jjgod Jiang <gzjjgod@gmail.com>
+Keith Packard <keithp@keithp.com>
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Mikhail Gusarov <dottedmag@dottedmag.net>
+Stewart Smith <stewart@flamingspork.com>
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "to addresses with any count"
+notmuch address --output=recipients --deduplicate=address --output=address \
+	--query=sexp '(to (count 1 *))' | sort >OUTPUT
+cat <<EOF >EXPECTED
+allan@archlinux.org
+aur-general@archlinux.org
+dottedmag@dottedmag.net
+keithp@keithp.com
+notmuch@notmuchmail.org
+olivier.berger@it-sudparis.eu
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "to addresses with unique words"
+notmuch address --query=sexp --output=recipients --output=address '(to (count 1))' | sort > OUTPUT
+cat <<EOF >EXPECTED
+allan@archlinux.org
+aur-general@archlinux.org
+dottedmag@dottedmag.net
+keithp@keithp.com
+notmuch@notmuchmail.org
+olivier.berger@it-sudparis.eu
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "to addresses with only non-unique words"
+notmuch address --output=recipients --deduplicate=address --output=address \
+	--query=sexp '(to (not (count 1)))' | sort > OUTPUT
+cat <<EOF >EXPECTED
+notmuch@notmuchmail.org
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
-- 
2.39.1
\r

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/6] WIP/test: pathname related tests
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
                   ` (2 preceding siblings ...)
  2023-02-18 17:17 ` [PATCH 3/6] WIP/test: (count ...) tests for to / from David Bremner
@ 2023-02-18 17:17 ` David Bremner
  2023-02-18 17:17 ` [PATCH 5/6] WIP/test: (count ...) tests David Bremner
  2023-02-18 17:17 ` [PATCH 6/6] WIP/tests: (count ...) tests for subject David Bremner
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

---
 test/T083-sexpr-count.sh | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/test/T083-sexpr-count.sh b/test/T083-sexpr-count.sh
index f3010d11..858aa8bf 100755
--- a/test/T083-sexpr-count.sh
+++ b/test/T083-sexpr-count.sh
@@ -112,4 +112,25 @@ notmuch@notmuchmail.org
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "attachment filenames with unique words"
+notmuch show --entire-thread=false --query=sexp '(attachment (count 1))' | \
+    sed -n -e 's/, Content-type:.*$//' -e 's/.*Filename: //p' | sort > OUTPUT
+cat <<EOF > EXPECTED
+0001-Deal-with-situation-where-sysconf-_SC_GETPW_R_SIZE_M.patch
+0001-Error-out-if-no-query-is-supplied-to-search-instead-.patch
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "messages in folders with several other messages"
+output=$(notmuch count --output=messages --query=sexp '(folder (count 28 *))')
+test_expect_equal "${output}" "28"
+
+test_begin_subtest "messages alone in a directory"
+notmuch search --output=messages --query=sexp '(path (count 1))' > OUTPUT
+cat <<EOF > EXPECTED
+id:87lji4lx9v.fsf@yoom.home.cworth.org
+id:87iqd9rn3l.fsf@vertex.dottedmag
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
-- 
2.39.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/6] WIP/test: (count ...) tests
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
                   ` (3 preceding siblings ...)
  2023-02-18 17:17 ` [PATCH 4/6] WIP/test: pathname related tests David Bremner
@ 2023-02-18 17:17 ` David Bremner
  2023-02-18 17:17 ` [PATCH 6/6] WIP/tests: (count ...) tests for subject David Bremner
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

The most interesting case is probably tags with a small number of
uses, since these could be typos or similar errors.
---
 test/T083-sexpr-count.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/test/T083-sexpr-count.sh b/test/T083-sexpr-count.sh
index 858aa8bf..1be3f62d 100755
--- a/test/T083-sexpr-count.sh
+++ b/test/T083-sexpr-count.sh
@@ -133,4 +133,12 @@ id:87iqd9rn3l.fsf@vertex.dottedmag
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "messages with tags used by 4 messages"
+output=$(notmuch count --output=messages --query=sexp '(tag (count 4))')
+test_expect_equal "${output}" "4"
+
+test_begin_subtest "no tag is used less than 4 times"
+output=$(notmuch count --output=messages --query=sexp '(tag (count * 3))')
+test_expect_equal "${output}" "0"
+
 test_done
-- 
2.39.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/6] WIP/tests:  (count ...) tests for subject
  2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
                   ` (4 preceding siblings ...)
  2023-02-18 17:17 ` [PATCH 5/6] WIP/test: (count ...) tests David Bremner
@ 2023-02-18 17:17 ` David Bremner
  5 siblings, 0 replies; 7+ messages in thread
From: David Bremner @ 2023-02-18 17:17 UTC (permalink / raw)
  To: notmuch

---
 test/T083-sexpr-count.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/test/T083-sexpr-count.sh b/test/T083-sexpr-count.sh
index 1be3f62d..b1c0a3ac 100755
--- a/test/T083-sexpr-count.sh
+++ b/test/T083-sexpr-count.sh
@@ -141,4 +141,12 @@ test_begin_subtest "no tag is used less than 4 times"
 output=$(notmuch count --output=messages --query=sexp '(tag (count * 3))')
 test_expect_equal "${output}" "0"
 
+test_begin_subtest "subjects with unique words"
+notmuch search --query=sexp '(and (from gusarov) (subject (count 1)))' | notmuch_search_sanitize > OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX   2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
+thread:XXX   2009-11-17 [1/5] Mikhail Gusarov| Carl Worth, Keith Packard; [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
-- 
2.39.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-02-18 17:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-18 17:17 WIP: add a (count ...) modifier for sexp-queries David Bremner
2023-02-18 17:17 ` [PATCH 1/6] WIP/lib: add count query backend David Bremner
2023-02-18 17:17 ` [PATCH 2/6] WIP/lib: support count modifier in sexp queries David Bremner
2023-02-18 17:17 ` [PATCH 3/6] WIP/test: (count ...) tests for to / from David Bremner
2023-02-18 17:17 ` [PATCH 4/6] WIP/test: pathname related tests David Bremner
2023-02-18 17:17 ` [PATCH 5/6] WIP/test: (count ...) tests David Bremner
2023-02-18 17:17 ` [PATCH 6/6] WIP/tests: (count ...) tests for subject David Bremner

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).