require "vnd.dovecot.testsuite";

require "envelope";

/*
 * Empty envelope addresses
 */

/* RFC 5228, Section 5.4: The null reverse-path is matched against as the empty
 * string, regardless of the ADDRESS-PART argument specified.
 */

test "Envelope - from empty" {
	/* Return_path: "" */

	test_set "envelope.from" "";

	if not envelope :all :is "from" "" {
		test_fail "failed to (:all :is)-match a \"\" return path";
	}

	if not envelope :all :contains "from" "" {
		test_fail "failed to (:all :contains)-match a \"\" return path";
	}

	if not envelope :domain :is "from" "" {
		test_fail "failed to (:domain :is)-match a \"\" return path";
	}

	if not envelope :domain :contains "from" "" {
		test_fail "failed to (:domain :contains)-match a \"\" return path";
	}

	/* Return path: <> */

	test_set "envelope.from" "<>";

	if not envelope :all :is "from" "" {
		test_fail "failed to (:all :is)-match a <> return path";
	}

	if not envelope :all :contains "from" "" {
		test_fail "failed to (:all :contains)-match a <> return path";
	}

	if not envelope :domain :is "from" "" {
		test_fail "failed to (:domain :is)-match a <> return path";
	}

	if not envelope :domain :contains "from" "" {
		test_fail "failed to (:domain :contains)-match a <> return path";
	}

	if envelope :all :is "from" "nico@frop.example.org" {
		test_fail "envelope test matches nonsense";
	}
}

/*
 * Invalid envelope addresses
 */

test "Envelope - invalid paths" {
	/* Return_path: "hutsefluts" */

	test_set "envelope.from" "hutsefluts@";
	test_set "envelope.to" "knurft@";

	if envelope :all :is "from" "hutsefluts@" {
		test_fail ":all address part matched syntactically incorrect reverse path";
	}
	if envelope :all :is "to" "knurft@" {
		test_fail ":all address part matched syntactically incorrect forward path";
	}
}

/*
 * Syntax errors
 */

test "Envelope - syntax errors" {
	/* Control */
	test_set "envelope.from" "<stephan@example.org>";
	if not envelope :all :is "from" "stephan@example.org" {
		test_fail "correct control test failed";
	}

	# Duplicate <
	test_set "envelope.from" "<<stephan@example.org>";
	if envelope :all :is "from" "stephan@example.org" {
		test_fail "failed to recognize syntax error (1)";
	}

	# Spurious >
	test_set "envelope.from" "stephan@example.org>";
	if envelope :all :is "from" "stephan@example.org" {
		test_fail "failed to recognize syntax error (2)";
	}

	# Missing >
	test_set "envelope.from" "<stephan@example.org";
	if envelope :all :is "from" "stephan@example.org" {
		test_fail "failed to recognize syntax error (3)";
	}

	# No @
	test_set "envelope.from" "<stephan example.org>";
	if envelope :domain :contains "from" "example" {
		test_fail "failed to recognize syntax error (4)";
	}

	# Duplicate @
	test_set "envelope.from" "<stephan@@example.org>";
	if envelope :domain :contains "from" "example" {
		test_fail "failed to recognize syntax error (5)";
	}
}

/*
 * Ignoring source routes
 */

test "Envelope - source route" {
	/* Single */
	test_set "envelope.from" "<@cola.example.org:stephan@example.org>";
	if not envelope :localpart :is "from" "stephan" {
		test_fail "parsing path with source route (single) failed";
	}

	/* Dual */
	test_set "envelope.from" "<@cola.example.org,@mx.utwente.nl:stephan@example.org>";
	if not envelope :localpart :is "from" "stephan" {
		test_fail "parsing path with source route (dual) failed";
	}

	/* Multiple */
	test_set "envelope.from" "<@cola.example.org,@mx.utwente.nl,@smtp.example.net:stephan@example.org>";
	if not envelope :localpart :is "from" "stephan" {
		test_fail "parsing path with source route (multiple) failed";
	}
}

test "Envelope - source route errors" {
	test_set "envelope.to" "<cola.example.org:stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (1)";
	}

	test_set "envelope.to" "<@.example.org:stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (2)";
	}

	test_set "envelope.to" "<@cola..nl:stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (3)";
	}

	test_set "envelope.to" "<@cola.example.orgstephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (4)";
	}

	test_set "envelope.to" "<@cola.example.org@mx.utwente.nl:stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (5)";
	}

	test_set "envelope.to" "<@cola.example.org,mx.utwente.nl:stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (6)";
	}

	test_set "envelope.to" "<@cola.example.org,@mx.utwente.nl,stephan@example.org>";
	if envelope :domain :contains "to" "" {
		test_fail "parsing syntactically incorrect path should have failed (7)";
	}
}

test "Envelope - local part only" {
	test_set "envelope.to" "<MAILER-DAEMON>";
	if not envelope :is "to" "MAILER-DAEMON" {
		test_fail "failed to parse local_part only path";
	}

	test_set "envelope.to" "MAILER-DAEMON@";
	if envelope :is "to" "MAILER-DAEMON" {
		test_fail "parsing syntactically incorrect path with missing domain";
	}

	test_set "envelope.to" "<MAILER-DAEMON>";
	if not envelope :is "to" "MAILER-DAEMON" {
		test_fail "failed to parse local_part only path with angle brackets";
	}
}

test "Envelope - Japanese localpart" {
	test_set "envelope.to" ".japanese@example.com";
	if not envelope :localpart :is "to" ".japanese" {
		test_fail "failed to parse japanese local_part (1)";
	}

	test_set "envelope.to" "japanese.@example.com";
	if not envelope :localpart :is "to" "japanese." {
		test_fail "failed to parse japanese local_part (2)";
	}

	test_set "envelope.to" "japanese...localpart@example.com";
	if not envelope :localpart :is "to" "japanese...localpart" {
		test_fail "failed to parse japanese local_part (3)";
	}

	test_set "envelope.to" "..japanese...localpart..@example.com";
	if not envelope :localpart :is "to" "..japanese...localpart.." {
		test_fail "failed to parse japanese local_part (4)";
	}
}

test "Envelope - Non-standard hostnames" {
	test_set "envelope.to" "japanese@_example.com";
	if not envelope :domain :is "to" "_example.com" {
		test_fail "failed to parse non-standard domain (1)";
	}

	test_set "envelope.to" "japanese@ex_ample.com";
	if not envelope :domain :is "to" "ex_ample.com" {
		test_fail "failed to parse non-standard domain (2)";
	}

	test_set "envelope.to" "japanese@example_.com";
	if not envelope :domain :is "to" "example_.com" {
		test_fail "failed to parse non-standard domain (3)";
	}

	test_set "envelope.to" "japanese@-example.com";
	if not envelope :domain :is "to" "-example.com" {
		test_fail "failed to parse non-standard domain (4)";
	}

	test_set "envelope.to" "japanese@example-.com";
	if not envelope :domain :is "to" "example-.com" {
		test_fail "failed to parse non-standard domain (5)";
	}
}
