| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <set> | 5 #include <set> |
| 6 #include <string> | 6 #include <string> |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 } | 794 } |
| 795 | 795 |
| 796 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 796 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 797 NonInteractiveMintFailure) { | 797 NonInteractiveMintFailure) { |
| 798 SignIn("primary@example.com"); | 798 SignIn("primary@example.com"); |
| 799 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 799 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 800 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 800 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 801 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); | 801 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); |
| 802 std::string error = | 802 std::string error = |
| 803 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); | 803 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); |
| 804 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 804 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 805 EXPECT_FALSE(func->login_ui_shown()); | 805 EXPECT_FALSE(func->login_ui_shown()); |
| 806 EXPECT_FALSE(func->scope_ui_shown()); | 806 EXPECT_FALSE(func->scope_ui_shown()); |
| 807 } | 807 } |
| 808 | 808 |
| 809 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 809 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 810 NonInteractiveLoginAccessTokenFailure) { | 810 NonInteractiveLoginAccessTokenFailure) { |
| 811 SignIn("primary@example.com"); | 811 SignIn("primary@example.com"); |
| 812 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 812 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 813 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 813 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 814 func->set_login_access_token_result(false); | 814 func->set_login_access_token_result(false); |
| 815 std::string error = utils::RunFunctionAndReturnError( | 815 std::string error = utils::RunFunctionAndReturnError( |
| 816 func.get(), "[{}]", browser()); | 816 func.get(), "[{}]", browser()); |
| 817 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 817 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 818 } | 818 } |
| 819 | 819 |
| 820 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 820 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 821 NonInteractiveMintAdviceSuccess) { | 821 NonInteractiveMintAdviceSuccess) { |
| 822 SignIn("primary@example.com"); | 822 SignIn("primary@example.com"); |
| 823 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); | 823 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 824 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 824 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 825 func->set_extension(extension.get()); | 825 func->set_extension(extension.get()); |
| 826 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); | 826 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); |
| 827 std::string error = | 827 std::string error = |
| 828 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); | 828 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); |
| 829 EXPECT_EQ(std::string(errors::kNoGrant), error); | 829 EXPECT_EQ(std::string(errors::kNoGrant), error); |
| 830 EXPECT_FALSE(func->login_ui_shown()); | 830 EXPECT_FALSE(func->login_ui_shown()); |
| 831 EXPECT_FALSE(func->scope_ui_shown()); | 831 EXPECT_FALSE(func->scope_ui_shown()); |
| 832 | 832 |
| 833 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, | 833 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, |
| 834 GetCachedToken(std::string()).status()); | 834 GetCachedToken(std::string()).status()); |
| 835 } | 835 } |
| 836 | 836 |
| 837 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 837 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 838 NonInteractiveMintBadCredentials) { | 838 NonInteractiveMintBadCredentials) { |
| 839 SignIn("primary@example.com"); | 839 SignIn("primary@example.com"); |
| 840 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 840 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 841 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 841 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 842 func->set_mint_token_result( | 842 func->set_mint_token_result( |
| 843 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS); | 843 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS); |
| 844 std::string error = | 844 std::string error = |
| 845 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); | 845 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); |
| 846 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 846 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 847 EXPECT_FALSE(func->login_ui_shown()); | 847 EXPECT_FALSE(func->login_ui_shown()); |
| 848 EXPECT_FALSE(func->scope_ui_shown()); | 848 EXPECT_FALSE(func->scope_ui_shown()); |
| 849 } | 849 } |
| 850 | 850 |
| 851 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 851 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 852 NonInteractiveMintServiceError) { | 852 NonInteractiveMintServiceError) { |
| 853 SignIn("primary@example.com"); | 853 SignIn("primary@example.com"); |
| 854 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 854 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 855 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 855 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 856 func->set_mint_token_result( | 856 func->set_mint_token_result( |
| 857 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR); | 857 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR); |
| 858 std::string error = | 858 std::string error = |
| 859 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); | 859 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); |
| 860 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 860 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 861 EXPECT_FALSE(func->login_ui_shown()); | 861 EXPECT_FALSE(func->login_ui_shown()); |
| 862 EXPECT_FALSE(func->scope_ui_shown()); | 862 EXPECT_FALSE(func->scope_ui_shown()); |
| 863 } | 863 } |
| 864 | 864 |
| 865 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 865 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 866 NoOptionsSuccess) { | 866 NoOptionsSuccess) { |
| 867 SignIn("primary@example.com"); | 867 SignIn("primary@example.com"); |
| 868 #if defined(OS_WIN) && defined(USE_ASH) | 868 #if defined(OS_WIN) && defined(USE_ASH) |
| 869 // Disable this test in Metro+Ash for now (http://crbug.com/262796). | 869 // Disable this test in Metro+Ash for now (http://crbug.com/262796). |
| 870 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 870 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 } | 952 } |
| 953 | 953 |
| 954 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 954 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 955 InteractiveLoginSuccessMintFailure) { | 955 InteractiveLoginSuccessMintFailure) { |
| 956 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 956 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 957 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 957 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 958 func->set_login_ui_result(true); | 958 func->set_login_ui_result(true); |
| 959 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); | 959 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); |
| 960 std::string error = utils::RunFunctionAndReturnError( | 960 std::string error = utils::RunFunctionAndReturnError( |
| 961 func.get(), "[{\"interactive\": true}]", browser()); | 961 func.get(), "[{\"interactive\": true}]", browser()); |
| 962 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 962 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 963 EXPECT_TRUE(func->login_ui_shown()); | 963 EXPECT_TRUE(func->login_ui_shown()); |
| 964 EXPECT_FALSE(func->scope_ui_shown()); | 964 EXPECT_FALSE(func->scope_ui_shown()); |
| 965 } | 965 } |
| 966 | 966 |
| 967 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 967 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 968 InteractiveLoginSuccessLoginAccessTokenFailure) { | 968 InteractiveLoginSuccessLoginAccessTokenFailure) { |
| 969 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 969 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 970 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 970 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 971 func->set_login_ui_result(true); | 971 func->set_login_ui_result(true); |
| 972 func->set_login_access_token_result(false); | 972 func->set_login_access_token_result(false); |
| 973 std::string error = utils::RunFunctionAndReturnError( | 973 std::string error = utils::RunFunctionAndReturnError( |
| 974 func.get(), "[{\"interactive\": true}]", browser()); | 974 func.get(), "[{\"interactive\": true}]", browser()); |
| 975 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 975 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 976 EXPECT_TRUE(func->login_ui_shown()); | 976 EXPECT_TRUE(func->login_ui_shown()); |
| 977 EXPECT_FALSE(func->scope_ui_shown()); | 977 EXPECT_FALSE(func->scope_ui_shown()); |
| 978 } | 978 } |
| 979 | 979 |
| 980 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 980 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 981 InteractiveLoginSuccessMintSuccess) { | 981 InteractiveLoginSuccessMintSuccess) { |
| 982 // TODO(courage): verify that account_id in token service requests | 982 // TODO(courage): verify that account_id in token service requests |
| 983 // is correct once manual token minting for tests is implemented. | 983 // is correct once manual token minting for tests is implemented. |
| 984 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 984 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 985 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 985 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 | 1069 |
| 1070 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 1070 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 1071 InteractiveApprovalConnectionFailure) { | 1071 InteractiveApprovalConnectionFailure) { |
| 1072 SignIn("primary@example.com"); | 1072 SignIn("primary@example.com"); |
| 1073 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 1073 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 1074 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 1074 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 1075 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); | 1075 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); |
| 1076 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR); | 1076 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR); |
| 1077 std::string error = utils::RunFunctionAndReturnError( | 1077 std::string error = utils::RunFunctionAndReturnError( |
| 1078 func.get(), "[{\"interactive\": true}]", browser()); | 1078 func.get(), "[{\"interactive\": true}]", browser()); |
| 1079 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 1079 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 1080 EXPECT_FALSE(func->login_ui_shown()); | 1080 EXPECT_FALSE(func->login_ui_shown()); |
| 1081 EXPECT_TRUE(func->scope_ui_shown()); | 1081 EXPECT_TRUE(func->scope_ui_shown()); |
| 1082 } | 1082 } |
| 1083 | 1083 |
| 1084 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 1084 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 1085 InteractiveApprovalOAuthErrors) { | 1085 InteractiveApprovalOAuthErrors) { |
| 1086 SignIn("primary@example.com"); | 1086 SignIn("primary@example.com"); |
| 1087 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); | 1087 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 1088 | 1088 |
| 1089 std::map<std::string, std::string> error_map; | 1089 std::map<std::string, std::string> error_map; |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 SignIn("primary@example.com"); | 1491 SignIn("primary@example.com"); |
| 1492 IssueLoginRefreshTokenForAccount("secondary@example.com"); | 1492 IssueLoginRefreshTokenForAccount("secondary@example.com"); |
| 1493 SetAccountState(CreateIds("primary@example.com", "1"), true); | 1493 SetAccountState(CreateIds("primary@example.com", "1"), true); |
| 1494 SetAccountState(CreateIds("secondary@example.com", "2"), true); | 1494 SetAccountState(CreateIds("secondary@example.com", "2"), true); |
| 1495 | 1495 |
| 1496 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 1496 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 1497 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 1497 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 1498 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); | 1498 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); |
| 1499 std::string error = utils::RunFunctionAndReturnError( | 1499 std::string error = utils::RunFunctionAndReturnError( |
| 1500 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); | 1500 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); |
| 1501 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 1501 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 1502 EXPECT_FALSE(func->login_ui_shown()); | 1502 EXPECT_FALSE(func->login_ui_shown()); |
| 1503 EXPECT_FALSE(func->scope_ui_shown()); | 1503 EXPECT_FALSE(func->scope_ui_shown()); |
| 1504 } | 1504 } |
| 1505 | 1505 |
| 1506 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 1506 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 1507 MultiSecondaryNonInteractiveLoginAccessTokenFailure) { | 1507 MultiSecondaryNonInteractiveLoginAccessTokenFailure) { |
| 1508 SignIn("primary@example.com"); | 1508 SignIn("primary@example.com"); |
| 1509 IssueLoginRefreshTokenForAccount("secondary@example.com"); | 1509 IssueLoginRefreshTokenForAccount("secondary@example.com"); |
| 1510 SetAccountState(CreateIds("primary@example.com", "1"), true); | 1510 SetAccountState(CreateIds("primary@example.com", "1"), true); |
| 1511 SetAccountState(CreateIds("secondary@example.com", "2"), true); | 1511 SetAccountState(CreateIds("secondary@example.com", "2"), true); |
| 1512 | 1512 |
| 1513 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 1513 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| 1514 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); | 1514 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
| 1515 func->set_login_access_token_result(false); | 1515 func->set_login_access_token_result(false); |
| 1516 std::string error = utils::RunFunctionAndReturnError( | 1516 std::string error = utils::RunFunctionAndReturnError( |
| 1517 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); | 1517 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); |
| 1518 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); | 1518 EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false)); |
| 1519 } | 1519 } |
| 1520 | 1520 |
| 1521 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, | 1521 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
| 1522 MultiSecondaryInteractiveApprovalAborted) { | 1522 MultiSecondaryInteractiveApprovalAborted) { |
| 1523 SignIn("primary@example.com"); | 1523 SignIn("primary@example.com"); |
| 1524 IssueLoginRefreshTokenForAccount("secondary@example.com"); | 1524 IssueLoginRefreshTokenForAccount("secondary@example.com"); |
| 1525 SetAccountState(CreateIds("primary@example.com", "1"), true); | 1525 SetAccountState(CreateIds("primary@example.com", "1"), true); |
| 1526 SetAccountState(CreateIds("secondary@example.com", "2"), true); | 1526 SetAccountState(CreateIds("secondary@example.com", "2"), true); |
| 1527 | 1527 |
| 1528 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); | 1528 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1826 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), | 1826 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), |
| 1827 url); | 1827 url); |
| 1828 } | 1828 } |
| 1829 | 1829 |
| 1830 } // namespace extensions | 1830 } // namespace extensions |
| 1831 | 1831 |
| 1832 // Tests the chrome.identity API implemented by custom JS bindings . | 1832 // Tests the chrome.identity API implemented by custom JS bindings . |
| 1833 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) { | 1833 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) { |
| 1834 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_; | 1834 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_; |
| 1835 } | 1835 } |
| OLD | NEW |