Compare commits

...
45 Commits
Author SHA1 Message Date
Wojtek Mach 7df646d960 Backport building docs_config.js (#12620)
Cherry-picked from https://github.com/elixir-lang/elixir/commit/6f2c669a98c33d3c98a50c023b0434bb79041c89
2023-05-30 10:21:42 +02:00
José ValimandEric Meadows-Jönsson 74fe558c17 Fix generated docs_config.js on CI (#12618) (#12619)
Co-authored-by: Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>
2023-05-30 09:47:54 +02:00
José Valim 7918d64700 Add branch docs publishing 2023-05-30 08:20:24 +02:00
José Valim 81d6007410 Release v1.14.5 2023-05-22 16:39:51 +02:00
José Valim be9fd499e6 Update Ubuntu instance 2023-05-22 16:39:25 +02:00
José Valim a5958e31a1 Release v1.14.5 2023-05-22 16:23:17 +02:00
Thanabodee Charoenpiriyakij 29067a0a7d Bump ubuntu to 20.04 (#12062)
The ubuntu-18.04 nows deprecated today [1]. This changes start moving it
to version 20.04 instead.

[1] https://github.com/actions/virtual-environments/issues/6002
2023-05-22 16:22:39 +02:00
José Valim ce8f0ac7d0 Release v1.14.5 2023-05-22 15:04:16 +02:00
José Valim 2d71e7144b Ensure conversion of maps to erlang ast is deterministic 2023-05-19 23:32:31 +02:00
José Valim 0c1395c215 Do not set encoding on Erlang/OTP 26 2023-05-18 11:55:24 +02:00
José Valim 1b3f9f8d5c Use httpc:ssl_verify_host_options/1 2023-04-07 11:28:02 +02:00
markovicmarko dbfdedf9b3 Update CHANGELOG.md (#12509)
Fix typo
2023-04-03 10:59:05 +02:00
José Valim 6f96693b35 Release v1.14.4 2023-04-03 09:33:52 +02:00
José Valim 4e5a8d48ba Update CHANGELOG 2023-04-03 09:31:59 +02:00
sabiwara acb5832c69 Fix dialyzer tests in OTP26 (#12486) 2023-04-03 09:28:11 +02:00
Zach Allaun f026cb3756 Fix column count when tokenizing escaped interpolations (#12504) 2023-03-30 23:04:21 +02:00
joepstender 73d58ec01b Fix typo in documentation (#12496) 2023-03-25 14:18:54 +01:00
José Valim e9a6c9e3b3 No need to revert trap exits 2023-03-24 23:17:23 +01:00
Kevin 237f3bc566 Backport test fixes (#12493) 2023-03-24 10:51:12 +01:00
Kevin 1a7545655c Update tests to new OTP start behaviour (#12490) 2023-03-23 15:23:52 +01:00
sabiwara 22fa810200 Fix logger formatting in OTP26 (#12434) 2023-03-23 14:12:40 +01:00
José Valim c3e0908c52 Clarify error message on missing certificates 2023-03-23 11:50:53 +01:00
Erick Dennis 3d0273afb3 Don't call formatter on directories (#12488) 2023-03-23 11:50:53 +01:00
Kevin 2b9d8b720e Add explicit :verify_none for httpc (#12485) 2023-03-23 11:50:22 +01:00
Andrea Leopardi 4687556f8f Add missing entry to CHANGELOG for v1.14.3 (#12468) 2023-03-15 09:20:07 +01:00
Alexandre a8824bab09 Fix Stream.zip/1 hanging on empty list (#12461) 2023-03-10 21:49:30 +01:00
José Valim 476b4fdf6e Bump timeout to infinity 2023-03-02 19:19:16 +01:00
Kevin 2229ed7924 Sort metadata before printing (#12440) 2023-03-02 11:34:46 +01:00
sabiwara f9c053d60c Make mix test reports deterministic in OTP26 (#12438)
* Make mix test reports deterministic in OTP26

The reports for the following were both relying on map keys ordering:
- mix test
- mix test.cover

* Fix non-deterministic test
2023-03-02 07:59:53 +01:00
sabiwara 1108a6c3d2 Fix more map inspection tests (#12433) 2023-02-28 12:56:27 +01:00
Shilov Konstantin 32c929b339 fix(supervisor): update documentation by call instead of cast (#12426) 2023-02-26 20:11:21 +01:00
José Valim 00e7245715 Update CHANGELOG 2023-02-23 15:09:03 +01:00
José Valim f596cf1629 Use get_until in IEx.Server
This change is necessary for forward compatibility
with Erlang/OTP 26+.
2023-02-23 15:08:03 +01:00
José Valim 12927b8840 Do not use private APIs in StringIO 2023-02-23 15:08:03 +01:00
José Valim 130ed60f4d Use infinity timeouts in parallel checker, closes #12421 2023-02-21 13:47:40 +01:00
José Valim 3eb94a482e Make sure protocols are loaded before dispatching
Closes https://github.com/hexpm/hex/issues/983.
2023-02-20 11:19:04 +01:00
sabiwara 6eca976752 Deterministic struct expansion (#12418) 2023-02-19 11:36:34 +01:00
sabiwara e977f023a0 Remove badfunc test on OTP26 (#12415) 2023-02-18 09:34:26 +01:00
sabiwara dc471cd876 Add :sort_maps to Inspect.Opts.custom_options (#12404) 2023-02-16 08:47:21 +01:00
sabiwara 6c31a6c8bb Fix Enum tests for maps in OTP26 (#12405) 2023-02-16 08:37:26 +01:00
José Valim 7535c0c403 Store complete path on quote keep, closes #12393 2023-02-13 12:56:31 +01:00
Zach Allaun 9fd9bceeaa Code.Normalizer: Use correct meta fields in normalize_call/2 (#12389) 2023-02-10 16:14:07 +01:00
José Valim 2ca0f1a99c Remove misplaced temporary files 2023-02-06 20:16:18 +01:00
Bram Verburg 6a1c5a449f Fix elixir_erl:debug_info/4 returning core_v1 (#12376) 2023-02-02 22:01:11 +01:00
José Valim c31d1b3eb0 Optimize application tracer 2023-01-28 11:31:07 +01:00
57 changed files with 622 additions and 213 deletions
+87
View File
@@ -0,0 +1,87 @@
name: builds.hex.pm
on:
push:
branches:
- main
- v*.*
tags:
- v*
env:
ELIXIR_OPTS: "--warnings-as-errors"
ERLC_OPTS: "warnings_as_errors"
LANG: C.UTF-8
concurrency: builds_txt
jobs:
release_pre_built:
strategy:
fail-fast: true
max-parallel: 1
matrix:
include:
- otp: 25
otp_version: '25.3'
build_docs: build_docs
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 50
- name: Get tags
run: git fetch --tags origin
- uses: ./.github/workflows/release_pre_built
with:
otp_version: ${{ matrix.otp_version }}
otp: ${{ matrix.otp }}
build_docs: ${{ matrix.build_docs }}
- name: Utils.sh
run: |
cat << 'EOF' > utils.sh
function purge_key() {
curl \
-X POST \
-H "Fastly-Key: ${FASTLY_KEY}" \
-H "Accept: application/json" \
-H "Content-Length: 0" \
"https://api.fastly.com/service/$1/purge/$2"
}
function purge() {
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
sleep 2
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
sleep 2
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
}
EOF
chmod +x utils.sh
- name: Upload Docs to S3
if: ${{ matrix.build_docs }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.HEX_AWS_REGION }}
AWS_S3_BUCKET: ${{ secrets.HEX_AWS_S3_BUCKET }}
FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
run: |
source utils.sh
version=$(echo ${{ github.ref_name }} | sed -e 's/^v//g')
for f in doc/*; do
if [ -d "$f" ]; then
app=`echo $f | sed s/"doc\/"//`
tarball="${app}-${version}.tar.gz"
surrogate_key="docs/${app}-${version}"
tar -czf "${tarball}" -C "doc/${app}" .
aws s3 cp "${tarball}" "s3://${{ env.AWS_S3_BUCKET }}/docs/${tarball}" \
--cache-control "public,max-age=3600" \
--metadata "{\"surrogate-key\":\"${surrogate_key}\",\"surrogate-control\":\"public,max-age=604800\"}"
purge "${surrogate_key}"
fi
done
+4 -4
View File
@@ -13,7 +13,7 @@ permissions:
jobs:
test_linux:
name: Linux, ${{ matrix.otp_release }}, Ubuntu 18.04
name: Linux, ${{ matrix.otp_release }}, Ubuntu 20.04
strategy:
fail-fast: false
matrix:
@@ -28,7 +28,7 @@ jobs:
development: true
- otp_release: maint
development: true
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@@ -36,7 +36,7 @@ jobs:
- name: Install Erlang/OTP
run: |
cd $RUNNER_TEMP
wget -O otp.tar.gz https://repo.hex.pm/builds/otp/ubuntu-18.04/${{ matrix.otp_release }}.tar.gz
wget -O otp.tar.gz https://repo.hex.pm/builds/otp/ubuntu-20.04/${{ matrix.otp_release }}.tar.gz
mkdir -p otp
tar zxf otp.tar.gz -C otp --strip-components=1
otp/Install -minimal $(pwd)/otp
@@ -113,7 +113,7 @@ jobs:
check_posix_compliant:
name: Check POSIX-compliant
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
+3 -3
View File
@@ -10,7 +10,7 @@ permissions:
jobs:
notify:
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
name: Notify
steps:
- uses: actions/checkout@v3
@@ -18,8 +18,8 @@ jobs:
fetch-depth: 50
- uses: erlef/setup-beam@v1
with:
otp-version: 24.3
elixir-version: 1.13.4
otp-version: '25.0'
elixir-version: '1.14.0'
- name: Run Elixir script
env:
ELIXIR_FORUM_TOKEN: ${{ secrets.ELIXIR_FORUM_TOKEN }}
+2 -2
View File
@@ -14,7 +14,7 @@ jobs:
create_draft_release:
permissions:
contents: write
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
@@ -39,7 +39,7 @@ jobs:
- otp: 25
otp_version: 25.0
build_docs: build_docs
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@@ -0,0 +1,51 @@
name: "Release pre built"
description: "Builds elixir release, ExDoc and generates docs"
inputs:
otp:
description: "The major OTP version"
otp_version:
description: "The exact OTP version (major.minor[.patch])"
build_docs:
description: "If docs have to be built or not"
runs:
using: "composite"
steps:
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ inputs.otp_version }}
version-type: strict
- name: Build Elixir Release
shell: bash
run: |
make Precompiled.zip
mv Precompiled.zip elixir-otp-${{ inputs.otp }}.zip
shasum -a 1 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha1sum
shasum -a 256 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha256sum
echo "$PWD/bin" >> $GITHUB_PATH
- name: Get latest stable ExDoc version
if: ${{ inputs.build_docs }}
shell: bash
run: |
EX_DOC_LATEST_STABLE_VERSION=$(curl -s https://hex.pm/api/packages/ex_doc | jq --raw-output '.latest_stable_version')
echo "EX_DOC_LATEST_STABLE_VERSION=${EX_DOC_LATEST_STABLE_VERSION}" >> $GITHUB_ENV
- uses: actions/checkout@v3
if: ${{ inputs.build_docs }}
with:
repository: elixir-lang/ex_doc
ref: v${{ env.EX_DOC_LATEST_STABLE_VERSION }}
path: ex_doc
- name: Build ex_doc
if: ${{ inputs.build_docs }}
shell: bash
run: |
mv ex_doc ../ex_doc
cd ../ex_doc
../elixir/bin/mix do local.rebar --force + local.hex --force + deps.get + compile
cd ../elixir
- name: Build Docs
if: ${{ inputs.build_docs }}
shell: bash
run: |
make Docs.zip
shasum -a 1 Docs.zip > Docs.zip.sha1sum
shasum -a 256 Docs.zip > Docs.zip.sha256sum
+57 -1
View File
@@ -241,6 +241,59 @@ protocol, giving developers more control over the struct representation.
See the updated documentation for `Inspect` for a general rundown on
the approaches and options available.
## v1.14.5 (2023-05-22)
This release contains fixes for Erlang/OTP 26.
### Bug fixes
#### Elixir
* [CLI] Fix a bug where stdout would block when there was no attached terminal on Windows when running on Erlang/OTP 26
#### Mix
* [Mix] Properly set SSL configuration for Mix downloads when running on Erlang/OTP 26
## v1.14.4 (2023-04-03)
This release adds basic support for Erlang/OTP 26. When migrating
to Erlang/OTP 26, keep it mind it changes how maps are stored
internally and they will be printed and traversed in a different
order (note maps never provided a guarantee of their order).
To aid migration, this release adds `:sort_maps` to `inspect`
custom options, in case you want to sort them before inspection:
inspect(map, custom_options: [sort_maps: true])
### Enhancements
#### Elixir
* [Inspect] Add `:sort_maps` to `Inspect.Opts.custom_options`
#### IEx
* [IEx] Support shell history in Erlang/OTP 26+
#### Mix
* [mix compile.elixir] Optimize application tracer
### Bug fixes
#### Elixir
* [Code] Properly handle blocks with comments in all cases in `Code.quoted_to_string_with_comments/2`
* [Kernel] Fix `debug_info/4` when returning core_v1
* [Kernel] Store complete path on `quote keep: true` to avoid invalid stacktraces
* [Kernel] Fix column count when tokenizing escaped interpolations
* [Stream] Fix `Stream.zip/1` hanging on empty list
#### Mix
* [mix format] Don't call formatter on directories
## v1.14.3 (2023-01-14)
### 1. Enhancements
@@ -259,14 +312,17 @@ the approaches and options available.
#### Elixir
* [Calendar] Fix handling of negative years in `Calendar.strftime/2`
* [DateTime] Consistently merge precision of subsecond operations (the bug was that subsecond precision was lost in functions like `DateTime.add/3`)
* [Exception] Improve blaming of FunctionClauseError with `is_struct/2` guards
* [Kernel] Fix invalid variable scoping in `defguard` expansion
* [Kernel] Do not warn on captured underscored vars from `defmodule`
* [Kernel] Do not crash for missing line info on type warnings
* [NaiveDateTime] Consistently merge precision of subsecond operations (the bug was that subsecond precision was lost in functions like `NaiveDateTime.add/3`)
* [Macro] Fix `Macro.to_string/1` for large negative integers
* [Macro] Properly type and escape expansion of `__ENV__` in macros
* [Path] Make sure `Path.wildcard/2` expands `..` symlinks accordingly
* [Range] Address corner cases in `Range.disjoint?/2` implementation
* [Time] Consistently merge precision of subsecond operations (the bug was that subsecond precision was lost in functions like `Time.add/3`)
#### ExUnit
@@ -466,7 +522,7 @@ the approaches and options available.
* [Module] Fix loop while unifying type variables
* [Protocol] Warn if a protocol has no definitions
* [Regex] Show list options when inspecting a Regex manually defined with `Regex.compile/2`
* [String] Allow slices to overflow on both starting and ending positions
* [String] Allow slices to overflow on both starting and ending positions
* [System] Raise non-generic exception on missing env in `System.fetch_env!/1` to mirror map operations
#### ExUnit
+15 -8
View File
@@ -181,39 +181,46 @@ clean_residual_files:
LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
SOURCE_REF = $(shell tag="$(call GIT_TAG)" revision="$(call GIT_REVISION)"; echo "$${tag:-$$revision}")
COMPILE_DOCS = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
DOCS_COMPILE = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
DOCS_CONFIG = bin/elixir lib/elixir/scripts/docs_config.exs "$(1)"
docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
docs_elixir: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (elixir)"
$(Q) rm -rf doc/elixir
$(call COMPILE_DOCS,Elixir,elixir,Kernel,--config "lib/elixir/docs.exs")
$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config "lib/elixir/scripts/elixir_docs.exs")
$(call DOCS_CONFIG,elixir)
docs_eex: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (eex)"
$(Q) rm -rf doc/eex
$(call COMPILE_DOCS,EEx,eex,EEx,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,EEx,eex,EEx,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,eex)
docs_mix: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (mix)"
$(Q) rm -rf doc/mix
$(call COMPILE_DOCS,Mix,mix,Mix,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,Mix,mix,Mix,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,mix)
docs_iex: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (iex)"
$(Q) rm -rf doc/iex
$(call COMPILE_DOCS,IEx,iex,IEx,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,IEx,iex,IEx,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,iex)
docs_ex_unit: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (ex_unit)"
$(Q) rm -rf doc/ex_unit
$(call COMPILE_DOCS,ExUnit,ex_unit,ExUnit,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,ExUnit,ex_unit,ExUnit,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,ex_unit)
docs_logger: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (logger)"
$(Q) rm -rf doc/logger
$(call COMPILE_DOCS,Logger,logger,Logger,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,Logger,logger,Logger,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,logger)
../ex_doc/bin/ex_doc:
@ echo "ex_doc is not found in ../ex_doc as expected. See README for more information."
@@ -228,7 +235,7 @@ Docs.zip: docs
Precompiled.zip: build_man compile
rm -f Precompiled.zip
zip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
zip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE Makefile man NOTICE README.md VERSION
@ echo "Precompiled file created $(CURDIR)/Precompiled.zip"
#==> Test tasks
+1 -1
View File
@@ -1 +1 @@
1.14.3
1.14.5
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/sh
set -e
ELIXIR_VERSION=1.14.3
ELIXIR_VERSION=1.14.5
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
cat <<USAGE >&2
+1 -1
View File
@@ -1,6 +1,6 @@
@if defined ELIXIR_CLI_ECHO (@echo on) else (@echo off)
set ELIXIR_VERSION=1.14.3
set ELIXIR_VERSION=1.14.5
setlocal enabledelayedexpansion
if ""%1""=="""" if ""%2""=="""" goto documentation
+1 -2
View File
@@ -361,8 +361,7 @@ defmodule NaiveDateTime do
`t:System.time_unit/0`. It defaults to `:second`. Negative values
will move backwards in time.
This function always consider the unit to be computed according
to the `Calendar.ISO`.
This function always considers the unit to be computed according to the `Calendar.ISO`.
## Examples
+2 -2
View File
@@ -362,7 +362,7 @@ defmodule Code.Normalizer do
normalize_kw_blocks(form, meta, args, state)
allow_keyword?(form, arity) ->
args = normalize_args(args, %{state | parent_meta: state.parent_meta})
args = normalize_args(args, %{state | parent_meta: meta})
{last_arg, leading_args} = List.pop_at(args, -1, [])
last_args =
@@ -384,7 +384,7 @@ defmodule Code.Normalizer do
{form, meta, leading_args ++ last_args}
true ->
args = normalize_args(args, %{state | parent_meta: state.parent_meta})
args = normalize_args(args, %{state | parent_meta: meta})
{form, meta, args}
end
end
+3 -3
View File
@@ -2276,13 +2276,13 @@ defmodule Enum do
iex> Enum.split_with([5, 4, 3, 2, 1, 0], fn x -> rem(x, 2) == 0 end)
{[4, 2, 0], [5, 3, 1]}
iex> Enum.split_with(%{a: 1, b: -2, c: 1, d: -3}, fn {_k, v} -> v < 0 end)
iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v < 0 end)
{[b: -2, d: -3], [a: 1, c: 1]}
iex> Enum.split_with(%{a: 1, b: -2, c: 1, d: -3}, fn {_k, v} -> v > 50 end)
iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v > 50 end)
{[], [a: 1, b: -2, c: 1, d: -3]}
iex> Enum.split_with(%{}, fn {_k, v} -> v > 50 end)
iex> Enum.split_with([], fn {_k, v} -> v > 50 end)
{[], []}
"""
+6 -1
View File
@@ -302,7 +302,12 @@ end
defimpl Inspect, for: Map do
def inspect(map, opts) do
list = Map.to_list(map)
list =
if Keyword.get(opts.custom_options, :sort_maps) do
map |> Map.to_list() |> :lists.sort()
else
Map.to_list(map)
end
fun =
if Inspect.List.keyword?(list) do
+5
View File
@@ -31,6 +31,11 @@ defmodule Inspect.Opts do
options. Useful when implementing the `Inspect` protocol for nested structs
to pass the custom options through.
It supports some pre-defined keys:
- `:sort_maps` (since v1.15.0) - if set to `true`, sorts key-value pairs in maps.
This can be helpful to make map inspection deterministic for testing,
especially since key order is random since OTP 26.
* `:inspect_fun` (since v1.9.0) - a function to build algebra documents.
Defaults to `Inspect.Opts.default_inspect_fun/0`.
+3 -1
View File
@@ -78,7 +78,9 @@ defmodule IO.ANSI.Docs do
@metadata_filter [:deprecated, :guard, :since]
defp print_each_metadata(metadata, options) do
Enum.reduce(metadata, false, fn
metadata
|> Enum.sort()
|> Enum.reduce(false, fn
{key, value}, _printed when is_binary(value) and key in @metadata_filter ->
label = metadata_label(key, options)
indent = String.duplicate(" ", length_without_escape(label, 0) + 1)
+2 -2
View File
@@ -145,7 +145,7 @@ defmodule Module.ParallelChecker do
spawn({self(), checker}, module, file)
end
modules = :gen_server.call(checker, :start)
modules = :gen_server.call(checker, :start, :infinity)
collect_results(modules, [])
end
@@ -171,7 +171,7 @@ defmodule Module.ParallelChecker do
"""
def test_cache do
{:ok, checker} = start_link()
{checker, :gen_server.call(checker, :ets)}
{checker, :gen_server.call(checker, :ets, :infinity)}
end
@doc """
+1 -1
View File
@@ -252,7 +252,7 @@ defmodule Module.Types do
"undefined field \"#{atom}\" ",
format_expr(expr, location),
"expected one of the following fields: ",
Enum.map_join(Enum.sort(known_atoms), ", ", & &1),
Enum.join(Enum.sort(known_atoms), ", "),
"\n\n",
traces,
format_message_hints(hints),
+2
View File
@@ -1315,6 +1315,8 @@ defmodule Stream do
{:suspended, acc, &zip_list(enumerables, &1, fun, zip_fun)}
end
defp zip_list([], {:cont, acc}, _fun, _zip_fun), do: {:done, acc}
defp zip_list(enumerables, {:cont, acc}, fun, zip_fun) do
case zip_list_heads_tails(enumerables, [], []) do
{heads, tails} -> zip_list(tails, fun.(zip_fun.(heads), acc), fun, zip_fun)
+2 -1
View File
@@ -366,6 +366,7 @@ defmodule StringIO do
defp get_until(encoding, prompt, mod, fun, args, %{input: input} = state) do
case get_until(input, encoding, mod, fun, args, [], 0) do
{result, input, count} ->
# Convert :eof to "" as they are both treated the same
input =
case input do
:eof -> ""
@@ -392,7 +393,7 @@ defmodule StringIO do
defp get_until(chars, encoding, mod, fun, args, continuation, count) do
case bytes_until_eol(chars, encoding, 0) do
{kind, size} when kind in [:split, :replace_split] ->
{line, rest} = :erlang.split_binary(chars, size)
<<line::binary-size(size), rest::binary>> = chars
case apply(mod, fun, [continuation, binary_to_list(line, encoding) | args]) do
{:done, result, :eof} ->
+1 -1
View File
@@ -82,7 +82,7 @@ defmodule Supervisor do
GenServer.call(Counter, :get)
#=> 0
GenServer.cast(Counter, {:bump, 3})
GenServer.call(Counter, {:bump, 3})
#=> 0
GenServer.call(Counter, :get)
@@ -42,7 +42,7 @@ Erlang/OTP versioning is independent from the versioning of Elixir. Erlang relea
Elixir version | Supported Erlang/OTP versions
:------------- | :-------------------------------
1.14 | 23 - 25
1.14 | 23 - 25 (and Erlang/OTP 26 from v1.14.5)
1.13 | 22 - 24 (and Erlang/OTP 25 from v1.13.4)
1.12 | 22 - 24
1.11 | 21 - 23 (and Erlang/OTP 24 from v1.11.4)
+19
View File
@@ -0,0 +1,19 @@
# Generate docs_config.js for version chooser in ExDoc
[app] = System.argv()
{text_tags, 0} = System.cmd("git", ["tag"])
skipped = Version.parse!("1.0.3")
list_contents =
text_tags
|> String.split()
|> Enum.map(fn "v" <> rest -> Version.parse!(rest) end)
|> Enum.filter(&(Version.compare(&1, skipped) == :gt))
|> Enum.sort({:desc, Version})
|> Enum.map_intersperse(", ", fn version ->
version_string = Version.to_string(version)
~s[{"version":"v#{version_string}", "url":"https://hexdocs.pm/#{app}/#{version_string}"}]
end)
File.mkdir_p!("doc/#{app}")
File.write!("doc/#{app}/docs_config.js", ["var versionNodes = [", list_contents, "];\n"])
+6 -3
View File
@@ -25,9 +25,9 @@
-export([start/2, stop/1, config_change/3]).
start(_Type, _Args) ->
_ = parse_otp_release(),
OTP = parse_otp_release(),
preload_common_modules(),
set_stdio_and_stderr_to_binary_and_maybe_utf8(),
set_stdio_and_stderr_to_binary_and_maybe_utf8(OTP),
check_file_encoding(file:native_name_encoding()),
case application:get_env(elixir, check_endianness, true) of
@@ -87,7 +87,10 @@ stop(Tab) ->
config_change(_Changed, _New, _Remove) ->
ok.
set_stdio_and_stderr_to_binary_and_maybe_utf8() ->
set_stdio_and_stderr_to_binary_and_maybe_utf8(OTP) when OTP >= 26 ->
ok = io:setopts(standard_io, [binary]),
ok;
set_stdio_and_stderr_to_binary_and_maybe_utf8(_OTP) ->
%% In case there is a shell, we can't really change its
%% encoding, so we just set binary to true. Otherwise
%% we must set the encoding as the user with no shell
+3 -2
View File
@@ -24,7 +24,7 @@ debug_info(core_v1, _Module, {elixir_v1, Map, Specs}, Opts) ->
%% warnings nor the other functionality provided there.
case elixir_erl_compiler:erl_to_core(Prefix ++ Specs ++ Forms, AllOpts) of
{ok, CoreForms, _} ->
try compile:noenv_forms(CoreForms, [no_spawn_compiler_process, from_core, core, return | AllOpts]) of
try compile:noenv_forms(CoreForms, [no_spawn_compiler_process, from_core, to_core, return | AllOpts]) of
{ok, _, Core, _} -> {ok, Core};
_What -> {error, failed_conversion}
catch
@@ -65,7 +65,8 @@ elixir_to_erl([], Ann) ->
elixir_to_erl(<<>>, Ann) ->
{bin, Ann, []};
elixir_to_erl(#{} = Map, Ann) ->
Assocs = [{map_field_assoc, Ann, elixir_to_erl(K, Ann), elixir_to_erl(V, Ann)} || {K, V} <- maps:to_list(Map)],
Assocs = [{map_field_assoc, Ann, elixir_to_erl(K, Ann), elixir_to_erl(V, Ann)}
|| {K, V} <- lists:sort(maps:to_list(Map))],
{map, Ann, Assocs};
elixir_to_erl(Tree, Ann) when is_list(Tree) ->
elixir_to_erl_cons(Tree, Ann);
+1 -1
View File
@@ -173,7 +173,7 @@ expand({quote, Meta, [Opts, Do]}, S, E) when is_list(Do) ->
{File, Line} = case lists:keyfind(location, 1, EOpts) of
{location, keep} ->
{elixir_utils:relative_to_cwd(?key(E, file)), false};
{?key(E, file), false};
false ->
{proplists:get_value(file, EOpts, nil), proplists:get_value(line, EOpts, false)}
end,
+1 -1
View File
@@ -39,7 +39,7 @@ extract([$\\, Last, Last, Last | Rest], Buffer, Output, Line, Column, Scope, Int
extract(Rest, [Last, Last, Last | Buffer], Output, Line, Column+4, Scope, Interpol, All);
extract([$\\, $#, ${ | Rest], Buffer, Output, Line, Column, Scope, true, Last) ->
extract(Rest, [${, $#, $\\ | Buffer], Output, Line, Column+1, Scope, true, Last);
extract(Rest, [${, $#, $\\ | Buffer], Output, Line, Column+3, Scope, true, Last);
extract([$#, ${ | Rest], Buffer, Output, Line, Column, Scope, true, Last) ->
Output1 = build_string(Buffer, Output),
+1 -1
View File
@@ -25,7 +25,7 @@ expand_struct(Meta, Left, {'%{}', MapMeta, MapArgs}, S, #{context := Context} =
AssocKeys = [K || {K, _} <- Assocs],
Struct = load_struct(Meta, ELeft, [Assocs], AssocKeys, EE),
Keys = ['__struct__'] ++ AssocKeys,
WithoutKeys = maps:to_list(maps:without(Keys, Struct)),
WithoutKeys = lists:sort(maps:to_list(maps:without(Keys, Struct))),
StructAssocs = elixir_quote:escape(WithoutKeys, none, false),
{{'%', Meta, [ELeft, {'%{}', MapMeta, StructAssocs ++ Assocs}]}, SE, EE};
@@ -507,6 +507,28 @@ defmodule Code.Normalizer.FormatterASTTest do
# after
""",
literal_encoder: fn literal, _ -> {:ok, literal} end
assert_same """
block do
# before 1
1 + 1
# before 2
2 + 2
end
""",
literal_encoder: fn literal, _ -> {:ok, literal} end
assert_same """
block do
# before 1
Mix.install([1 + 1])
# before 2
Mix.install([2 + 2])
end
""",
literal_encoder: fn literal, _ -> {:ok, literal} end
end
test "before and after expressions with newlines" do
+61 -64
View File
@@ -735,11 +735,11 @@ defmodule EnumTest do
assert Enum.split_with(%{}, fn x -> rem(x, 2) == 0 end) == {[], []}
assert Enum.split_with(%{a: 1, b: 2, c: 3}, fn {_k, v} -> rem(v, 2) == 0 end) ==
{[b: 2], [a: 1, c: 3]}
assert Enum.split_with(%{a: 1, b: 2}, fn {_k, v} -> rem(v, 2) == 0 end) ==
{[b: 2], [a: 1]}
assert Enum.split_with(%{b: 2, d: 4, f: 6}, fn {_k, v} -> rem(v, 2) == 0 end) ==
{[b: 2, d: 4, f: 6], []}
{Map.to_list(%{b: 2, d: 4, f: 6}), []}
end
test "random/1" do
@@ -1503,14 +1503,11 @@ defmodule EnumTest do
assert result == [2, 4, 6, 8, 10]
# Maps
result = Enum.zip_with(%{a: 7, c: 9}, 3..4, fn {key, value}, b -> {key, value + b} end)
assert result == [a: 10, c: 13]
result = Enum.zip_with(%{a: 7}, 3..4, fn {key, value}, b -> {key, value + b} end)
assert result == [a: 10]
colour_1 = %{r: 176, g: 175, b: 255}
colour_2 = %{r: 12, g: 176, b: 176}
result = Enum.zip_with(colour_1, colour_2, fn {k, left}, {k, right} -> {k, left + right} end)
assert result == [b: 431, g: 351, r: 188]
result = Enum.zip_with(3..4, %{a: 7}, fn a, {key, value} -> {key, value + a} end)
assert result == [a: 10]
end
test "zip_with/2" do
@@ -1518,8 +1515,10 @@ defmodule EnumTest do
result = Enum.zip_with([[:a, :b], [1, 2], ["foo", "bar"]], zip_fun)
assert result == [{:a, 1, "foo"}, {:b, 2, "bar"}]
lots = Enum.zip_with([[:a, :b], [1, 2], ["foo", "bar"], %{a: :b, c: :d}], zip_fun)
assert lots == [{:a, 1, "foo", {:a, :b}}, {:b, 2, "bar", {:c, :d}}]
map = %{a: :b, c: :d}
[x1, x2] = Map.to_list(map)
lots = Enum.zip_with([[:a, :b], [1, 2], ["foo", "bar"], map], zip_fun)
assert lots == [{:a, 1, "foo", x1}, {:b, 2, "bar", x2}]
assert Enum.zip_with([[:a, :b], [1, 2, 3, 4], ["foo", "bar", "baz", "qux"]], zip_fun) ==
[{:a, 1, "foo"}, {:b, 2, "bar"}]
@@ -1556,21 +1555,11 @@ defmodule EnumTest do
assert result == [2, 4, 6, 8, 10]
# Maps
result = Enum.zip_with([%{a: 7, c: 9}, 3..4], fn [{key, value}, b] -> {key, value + b} end)
assert result == [a: 10, c: 13]
result = Enum.zip_with([%{a: 7}, 3..4], fn [{key, value}, b] -> {key, value + b} end)
assert result == [a: 10]
colour_1 = %{r: 176, g: 175, b: 255}
colour_2 = %{r: 12, g: 176, b: 176}
result =
Enum.zip_with([colour_1, colour_2], fn [{k, left}, {k, right}] -> {k, left + right} end)
assert result == [b: 431, g: 351, r: 188]
assert Enum.zip_with([%{a: :b, c: :d}, %{e: :f, g: :h}], & &1) == [
[a: :b, e: :f],
[c: :d, g: :h]
]
result = Enum.zip_with([%{a: 7}, 3..4], fn [{key, value}, b] -> {key, value + b} end)
assert result == [a: 10]
end
end
@@ -2396,16 +2385,17 @@ defmodule EnumTest.Map do
test "random/1" do
map = %{a: 1, b: 2, c: 3}
[x1, x2, x3] = Map.to_list(map)
seed1 = {1406, 407_414, 139_258}
seed2 = {1406, 421_106, 567_597}
:rand.seed(:exsss, seed1)
assert Enum.random(map) == {:c, 3}
assert Enum.random(map) == {:a, 1}
assert Enum.random(map) == {:b, 2}
assert Enum.random(map) == x3
assert Enum.random(map) == x1
assert Enum.random(map) == x2
:rand.seed(:exsss, seed2)
assert Enum.random(map) == {:c, 3}
assert Enum.random(map) == {:b, 2}
assert Enum.random(map) == x3
assert Enum.random(map) == x2
end
test "take_random/2" do
@@ -2418,35 +2408,37 @@ defmodule EnumTest.Map do
# set a fixed seed so the test can be deterministic
# please note the order of following assertions is important
map = %{a: 1, b: 2, c: 3}
[x1, x2, x3] = Map.to_list(map)
seed1 = {1406, 407_414, 139_258}
seed2 = {1406, 421_106, 567_597}
:rand.seed(:exsss, seed1)
assert Enum.take_random(map, 1) == [c: 3]
assert Enum.take_random(map, 1) == [x3]
:rand.seed(:exsss, seed1)
assert Enum.take_random(map, 2) == [c: 3, a: 1]
assert Enum.take_random(map, 2) == [x3, x1]
:rand.seed(:exsss, seed1)
assert Enum.take_random(map, 3) == [c: 3, a: 1, b: 2]
assert Enum.take_random(map, 3) == [x3, x1, x2]
:rand.seed(:exsss, seed1)
assert Enum.take_random(map, 4) == [c: 3, a: 1, b: 2]
assert Enum.take_random(map, 4) == [x3, x1, x2]
:rand.seed(:exsss, seed2)
assert Enum.take_random(map, 1) == [a: 1]
assert Enum.take_random(map, 1) == [x1]
:rand.seed(:exsss, seed2)
assert Enum.take_random(map, 2) == [a: 1, c: 3]
assert Enum.take_random(map, 2) == [x1, x3]
:rand.seed(:exsss, seed2)
assert Enum.take_random(map, 3) == [a: 1, c: 3, b: 2]
assert Enum.take_random(map, 3) == [x1, x3, x2]
:rand.seed(:exsss, seed2)
assert Enum.take_random(map, 4) == [a: 1, c: 3, b: 2]
assert Enum.take_random(map, 4) == [x1, x3, x2]
end
test "reverse/1" do
assert Enum.reverse(%{}) == []
assert Enum.reverse(MapSet.new()) == []
assert Enum.reverse(%{a: 1, b: 2, c: 3}) == [c: 3, b: 2, a: 1]
map = %{a: 1, b: 2, c: 3}
assert Enum.reverse(map) == Map.to_list(map) |> Enum.reverse()
end
test "reverse/2" do
assert Enum.reverse([a: 1, b: 2, c: 3, a: 1], %{x: 1, y: 2, z: 3}) ==
[a: 1, c: 3, b: 2, a: 1, x: 1, y: 2, z: 3]
assert Enum.reverse([a: 1, b: 2, c: 3, a: 1], %{x: 1}) == [a: 1, c: 3, b: 2, a: 1, x: 1]
assert Enum.reverse([], %{a: 1}) == [a: 1]
assert Enum.reverse([], %{}) == []
@@ -2456,44 +2448,49 @@ defmodule EnumTest.Map do
test "fetch/2" do
map = %{a: 1, b: 2, c: 3, d: 4, e: 5}
assert Enum.fetch(map, 0) == {:ok, {:a, 1}}
assert Enum.fetch(map, -2) == {:ok, {:d, 4}}
[x1, _x2, _x3, x4, x5] = Map.to_list(map)
assert Enum.fetch(map, 0) == {:ok, x1}
assert Enum.fetch(map, -2) == {:ok, x4}
assert Enum.fetch(map, -6) == :error
assert Enum.fetch(map, 5) == :error
assert Enum.fetch(%{}, 0) == :error
assert Stream.take(map, 3) |> Enum.fetch(3) == :error
assert Stream.take(map, 5) |> Enum.fetch(4) == {:ok, {:e, 5}}
assert Stream.take(map, 5) |> Enum.fetch(4) == {:ok, x5}
end
test "map_intersperse/3" do
assert Enum.map_intersperse(%{}, :a, & &1) == []
assert Enum.map_intersperse(%{foo: :bar}, :a, & &1) == [{:foo, :bar}]
assert Enum.map_intersperse(%{foo: :bar, baz: :bat}, :a, & &1) ==
[{:baz, :bat}, :a, {:foo, :bar}]
map = %{foo: :bar, baz: :bat}
[x1, x2] = Map.to_list(map)
assert Enum.map_intersperse(map, :a, & &1) == [x1, :a, x2]
end
test "slice/2" do
map = %{a: 1, b: 2, c: 3, d: 4, e: 5}
assert Enum.slice(map, 0..0) == [a: 1]
assert Enum.slice(map, 0..1) == [a: 1, b: 2]
assert Enum.slice(map, 0..2) == [a: 1, b: 2, c: 3]
[x1, x2, x3 | _] = Map.to_list(map)
assert Enum.slice(map, 0..0) == [x1]
assert Enum.slice(map, 0..1) == [x1, x2]
assert Enum.slice(map, 0..2) == [x1, x2, x3]
end
test "slice/3" do
map = %{a: 1, b: 2, c: 3, d: 4, e: 5}
assert Enum.slice(map, 1, 2) == [b: 2, c: 3]
[x1, x2, x3, x4, x5] = Map.to_list(map)
assert Enum.slice(map, 1, 2) == [x2, x3]
assert Enum.slice(map, 1, 0) == []
assert Enum.slice(map, 2, 5) == [c: 3, d: 4, e: 5]
assert Enum.slice(map, 2, 6) == [c: 3, d: 4, e: 5]
assert Enum.slice(map, 2, 5) == [x3, x4, x5]
assert Enum.slice(map, 2, 6) == [x3, x4, x5]
assert Enum.slice(map, 5, 5) == []
assert Enum.slice(map, 6, 5) == []
assert Enum.slice(map, 6, 0) == []
assert Enum.slice(map, -6, 0) == []
assert Enum.slice(map, -6, 5) == [a: 1, b: 2, c: 3, d: 4, e: 5]
assert Enum.slice(map, -2, 5) == [d: 4, e: 5]
assert Enum.slice(map, -3, 1) == [c: 3]
assert Enum.slice(map, -6, 5) == [x1, x2, x3, x4, x5]
assert Enum.slice(map, -2, 5) == [x4, x5]
assert Enum.slice(map, -3, 1) == [x3]
assert_raise FunctionClauseError, fn ->
Enum.slice(map, 0, -1)
@@ -2508,19 +2505,19 @@ defmodule EnumTest.Map do
end
assert Enum.slice(map, 0, 0) == []
assert Enum.slice(map, 0, 1) == [a: 1]
assert Enum.slice(map, 0, 2) == [a: 1, b: 2]
assert Enum.slice(map, 1, 2) == [b: 2, c: 3]
assert Enum.slice(map, 0, 1) == [x1]
assert Enum.slice(map, 0, 2) == [x1, x2]
assert Enum.slice(map, 1, 2) == [x2, x3]
assert Enum.slice(map, 1, 0) == []
assert Enum.slice(map, 2, 5) == [c: 3, d: 4, e: 5]
assert Enum.slice(map, 2, 6) == [c: 3, d: 4, e: 5]
assert Enum.slice(map, 2, 5) == [x3, x4, x5]
assert Enum.slice(map, 2, 6) == [x3, x4, x5]
assert Enum.slice(map, 5, 5) == []
assert Enum.slice(map, 6, 5) == []
assert Enum.slice(map, 6, 0) == []
assert Enum.slice(map, -6, 0) == []
assert Enum.slice(map, -6, 5) == [a: 1, b: 2, c: 3, d: 4, e: 5]
assert Enum.slice(map, -2, 5) == [d: 4, e: 5]
assert Enum.slice(map, -3, 1) == [c: 3]
assert Enum.slice(map, -6, 5) == [x1, x2, x3, x4, x5]
assert Enum.slice(map, -2, 5) == [x4, x5]
assert Enum.slice(map, -3, 1) == [x3]
assert_raise FunctionClauseError, fn ->
Enum.slice(map, 0, -1)
+13 -6
View File
@@ -18,13 +18,20 @@ defmodule ExceptionTest do
end
end
assert Exception.message(%{__struct__: BadException, __exception__: true, raise: true}) =~
"got RuntimeError with message \"oops\" while retrieving Exception.message/1 " <>
"for %{__exception__: true, __struct__: ExceptionTest.BadException, raise: true}"
assert "got RuntimeError with message \"oops\" while retrieving Exception.message/1 for %{" <>
inspected =
Exception.message(%{__struct__: BadException, __exception__: true, raise: true})
assert Exception.message(%{__struct__: BadException, __exception__: true, raise: false}) =~
"got nil while retrieving Exception.message/1 " <>
"for %{__exception__: true, __struct__: ExceptionTest.BadException, raise: false}"
assert inspected =~ "raise: true"
assert inspected =~ "__exception__: true"
assert inspected =~ "__struct__: ExceptionTest.BadException"
assert "got nil while retrieving Exception.message/1 for %{" <> inspected =
Exception.message(%{__struct__: BadException, __exception__: true, raise: false})
assert inspected =~ "raise: false"
assert inspected =~ "__exception__: true"
assert inspected =~ "__struct__: ExceptionTest.BadException"
end
test "normalize/2" do
+22 -11
View File
@@ -417,14 +417,20 @@ defmodule Inspect.MapTest do
test "basic" do
assert inspect(%{1 => "b"}) == "%{1 => \"b\"}"
assert inspect(%{1 => "b", 2 => "c"}, pretty: true, width: 1) ==
assert inspect(%{1 => "b", 2 => "c"},
pretty: true,
width: 1,
custom_options: [sort_maps: true]
) ==
"%{\n 1 => \"b\",\n 2 => \"c\"\n}"
end
test "keyword" do
assert inspect(%{a: 1}) == "%{a: 1}"
assert inspect(%{a: 1, b: 2}) == "%{a: 1, b: 2}"
assert inspect(%{a: 1, b: 2, c: 3}) == "%{a: 1, b: 2, c: 3}"
assert inspect(%{a: 1, b: 2}, custom_options: [sort_maps: true]) == "%{a: 1, b: 2}"
assert inspect(%{a: 1, b: 2, c: 3}, custom_options: [sort_maps: true]) ==
"%{a: 1, b: 2, c: 3}"
end
test "with limit" do
@@ -446,12 +452,12 @@ defmodule Inspect.MapTest do
test "public modified struct" do
public = %Public{key: 1}
assert inspect(Map.put(public, :foo, :bar)) ==
assert inspect(Map.put(public, :foo, :bar), custom_options: [sort_maps: true]) ==
"%{__struct__: Inspect.MapTest.Public, foo: :bar, key: 1}"
end
test "private struct" do
assert inspect(%{__struct__: Private, key: 1}) ==
assert inspect(%{__struct__: Private, key: 1}, custom_options: [sort_maps: true]) ==
"%{__struct__: Inspect.MapTest.Private, key: 1}"
end
@@ -486,7 +492,7 @@ defmodule Inspect.MapTest do
%{__struct__: Inspect.MapTest.Failing, name: "Foo"}
'''
assert inspect(%Failing{name: "Foo"}) =~ message
assert inspect(%Failing{name: "Foo"}, custom_options: [sort_maps: true]) =~ message
end
test "safely inspect bad implementation disables colors" do
@@ -505,7 +511,10 @@ defmodule Inspect.MapTest do
%{__struct__: Inspect.MapTest.Failing, name: "Foo"}
'''
assert inspect(%Failing{name: "Foo"}, syntax_colors: [atom: [:green]]) =~ message
assert inspect(%Failing{name: "Foo"},
syntax_colors: [atom: [:green]],
custom_options: [sort_maps: true]
) =~ message
end
test "unsafely inspect bad implementation" do
@@ -524,7 +533,7 @@ defmodule Inspect.MapTest do
'''
try do
inspect(%Failing{name: "Foo"}, safe: false)
inspect(%Failing{name: "Foo"}, safe: false, custom_options: [sort_maps: true])
rescue
exception in Inspect.Error ->
assert Exception.message(exception) =~ exception_message
@@ -552,14 +561,16 @@ defmodule Inspect.MapTest do
while inspecting:
%{__struct__: Inspect.MapTest.Failing, name: "Foo"}
'''
try do
Enum.to_list(%Failing{name: "Foo"})
rescue
exception in Protocol.UndefinedError ->
assert Exception.message(exception) =~ exception_message
message = Exception.message(exception)
assert message =~ exception_message
assert message =~ "__struct__: Inspect.MapTest.Failing"
assert message =~ "name: \"Foo\""
assert [
{Enumerable, :impl_for!, 1, _} | _
@@ -617,7 +628,7 @@ defmodule Inspect.MapTest do
)
)
assert inspect(%Failing{name: "Foo"}) =~ message
assert inspect(%Failing{name: "Foo"}, custom_options: [sort_maps: true]) =~ message
assert inspected =~ message
end
@@ -22,7 +22,26 @@ defmodule Kernel.DialyzerTest do
end
# Add a few key Elixir modules for types and macro functions
mods = [:elixir, :elixir_env, Atom, Enum, Exception, Kernel, Macro, Macro.Env, String]
mods = [
:elixir,
:elixir_env,
ArgumentError,
Atom,
Enum,
Exception,
ExUnit.AssertionError,
ExUnit.Assertions,
IO,
Kernel,
Kernel.Utils,
List,
Macro,
Macro.Env,
Module,
String,
String.Chars
]
files = Enum.map(mods, &:code.which/1)
dialyzer_run(analysis_type: :plt_build, output_plt: plt, apps: [:erts], files: files)
@@ -102,6 +121,7 @@ defmodule Kernel.DialyzerTest do
copy_beam!(context, ProtocolOpaque)
copy_beam!(context, ProtocolOpaque.Entity)
copy_beam!(context, ProtocolOpaque.Entity.Any)
copy_beam!(context, ProtocolOpaque.Duck)
assert_dialyze_no_warnings!(context)
+1 -1
View File
@@ -21,7 +21,7 @@ defmodule Kernel.QuoteTest do
line = __ENV__.line + 2
assert quote(location: :keep, do: bar(1, 2, 3)) ==
{:bar, [keep: {Path.relative_to_cwd(__ENV__.file), line}], [1, 2, 3]}
{:bar, [keep: {__ENV__.file, line}], [1, 2, 3]}
end
test "fixed line" do
@@ -411,6 +411,7 @@ defmodule Kernel.RaiseTest do
fun = BadFunction.Missing.fun()
:code.delete(BadFunction.Missing)
:code.purge(BadFunction.Missing)
defmodule BadFunction.Missing do
def fun, do: fn -> :another end
+1 -1
View File
@@ -206,7 +206,7 @@ defmodule MapTest do
assert Map.replace!(map, :b, 10) == %{c: 3, b: 10, a: 1}
assert Map.replace!(map, :a, 1) == map
assert_raise KeyError, "key :x not found in: %{a: 1, b: 2, c: 3}", fn ->
assert_raise KeyError, ~r/key :x not found in: %{.*a: 1.*}/, fn ->
Map.replace!(map, :x, 10)
end
@@ -140,25 +140,25 @@ defmodule Module.Types.PatternTest do
end
test "struct" do
assert quoted_pattern(%:"Elixir.Module.Types.PatternTest.Struct"{}) ==
{:ok,
{:map,
[
{:required, {:atom, :__struct__}, {:atom, Module.Types.PatternTest.Struct}},
{:required, {:atom, :bar}, :dynamic},
{:required, {:atom, :baz}, :dynamic},
{:required, {:atom, :foo}, :dynamic}
]}}
assert {:ok, {:map, fields}} = quoted_pattern(%:"Elixir.Module.Types.PatternTest.Struct"{})
assert quoted_pattern(%:"Elixir.Module.Types.PatternTest.Struct"{foo: 123, bar: :atom}) ==
{:ok,
{:map,
[
{:required, {:atom, :foo}, :integer},
{:required, {:atom, :bar}, {:atom, :atom}},
{:required, {:atom, :__struct__}, {:atom, Module.Types.PatternTest.Struct}},
{:required, {:atom, :baz}, :dynamic}
]}}
assert Enum.sort(fields) == [
{:required, {:atom, :__struct__}, {:atom, Module.Types.PatternTest.Struct}},
{:required, {:atom, :bar}, :dynamic},
{:required, {:atom, :baz}, :dynamic},
{:required, {:atom, :foo}, :dynamic}
]
assert {:ok, {:map, fields}} =
quoted_pattern(%:"Elixir.Module.Types.PatternTest.Struct"{foo: 123, bar: :atom})
assert Enum.sort(fields) ==
[
{:required, {:atom, :__struct__}, {:atom, Module.Types.PatternTest.Struct}},
{:required, {:atom, :bar}, {:atom, :atom}},
{:required, {:atom, :baz}, :dynamic},
{:required, {:atom, :foo}, :integer}
]
end
test "struct var" do
+2
View File
@@ -1340,6 +1340,8 @@ defmodule StreamTest do
assert Stream.chunk_every([0, 1, 2, 3], 2) |> Stream.zip() |> Enum.to_list() ==
[{0, 2}, {1, 3}]
assert Stream.zip([]) |> Enum.to_list() == []
stream = %HaltAcc{acc: 1..3}
assert Stream.zip([1..3, stream]) |> Enum.to_list() == [{1, 1}, {2, 2}, {3, 3}]
+1 -1
View File
@@ -22,7 +22,7 @@ extract_interpolations_without_interpolation_test() ->
extract_interpolations_with_escaped_interpolation_test() ->
["f\\#{o}o"] = extract_interpolations("f\\#{o}o"),
{1, 8, ["f\\#{o}o"], [], _} =
{1, 10, ["f\\#{o}o"], [], _} =
elixir_interpolation:extract(1, 2, #elixir_tokenizer{}, true, "f\\#{o}o\"", $").
extract_interpolations_with_interpolation_test() ->
@@ -199,6 +199,11 @@ interpolation_test() ->
{concat_op, {1, 10, nil}, '<>'},
{bin_string, {1, 13, nil}, [<<>>]}] = tokenize("\"f#{oo}\" <> \"\"").
escaped_interpolation_test() ->
[{bin_string, {1, 1, nil}, [<<"f#{oo}">>]},
{concat_op, {1, 11, nil}, '<>'},
{bin_string, {1, 14, nil}, [<<>>]}] = tokenize("\"f\\#{oo}\" <> \"\"").
capture_test() ->
% Parens precedence
[{capture_op, {1, 1, nil}, '&'},
+3 -1
View File
@@ -337,7 +337,9 @@ defmodule ExUnit.CLIFormatter do
end
defp format_test_type_counts(%{test_counter: test_counter} = _config) do
Enum.map(test_counter, fn {test_type, count} ->
test_counter
|> Enum.sort()
|> Enum.map(fn {test_type, count} ->
type_pluralized = pluralize(count, test_type, ExUnit.plural_rule(test_type |> to_string()))
"#{count} #{type_pluralized}, "
end)
+4 -1
View File
@@ -523,7 +523,10 @@ defmodule IEx.Helpers do
:code.get_path()
|> Protocol.extract_protocols()
|> Enum.uniq()
|> Enum.reject(fn protocol -> is_nil(protocol.impl_for(term)) end)
|> Enum.filter(fn protocol ->
Code.ensure_loaded?(protocol) and function_exported?(protocol, :impl_for, 1) and
protocol.impl_for(term) != nil
end)
|> Enum.sort()
|> Enum.map_join(", ", &inspect/1)
end
+21 -1
View File
@@ -374,9 +374,29 @@ defmodule IEx.Server do
defp io_get(pid, prompt_type, prefix, counter) do
prompt = prompt(prompt_type, prefix, counter)
send(pid, {:input, self(), IO.gets(:stdio, prompt)})
send(pid, {:input, self(), io_get(prompt)})
end
defp io_get(prompt) do
pid = Process.group_leader()
ref = Process.monitor(pid)
command = {:get_until, :unicode, prompt, __MODULE__, :__io_get__, []}
send(pid, {:io_request, self(), ref, command})
receive do
{:io_reply, ^ref, reply} ->
Process.demonitor(ref, [:flush])
reply
{:DOWN, ^ref, _, _, _} ->
{:error, :terminated}
end
end
@doc false
def __io_get__([], :eof), do: {:done, :eof, []}
def __io_get__([], chars), do: {:done, List.to_string(chars), []}
defp prompt(prompt_type, prefix, counter) do
{mode, prefix} =
if Node.alive?() do
+3 -3
View File
@@ -31,9 +31,9 @@ defmodule IEx.AutocompleteTest do
end
test "Erlang module multiple values completion" do
{:yes, '', list} = expand(':user')
assert 'user' in list
assert 'user_drv' in list
{:yes, '', list} = expand(':logger')
assert 'logger' in list
assert 'logger_proxy' in list
end
test "Erlang root completion" do
+7 -2
View File
@@ -126,8 +126,13 @@ defmodule IEx.InteractionTest do
test "inspect opts" do
opts = [inspect: [binaries: :as_binaries, charlists: :as_lists, structs: false, limit: 4]]
assert capture_iex("<<45, 46, 47>>\n[45, 46, 47]\n%IO.Stream{}", opts) ==
"<<45, 46, 47>>\n[45, 46, 47]\n%{__struct__: IO.Stream, device: nil, line_or_bytes: :line, raw: true}"
assert "<<45, 46, 47>>\n[45, 46, 47]\n%{" <> map =
capture_iex("<<45, 46, 47>>\n[45, 46, 47]\n%IO.Stream{}", opts)
assert map =~ "__struct__: IO.Stream"
assert map =~ "device: nil"
assert map =~ "line_or_bytes: :line"
assert map =~ "raw: true"
end
test "exception" do
+2 -1
View File
@@ -134,7 +134,8 @@ defmodule Logger.Utils do
pad_char: ?\s,
precision: :none,
strings: true,
width: :none
width: :none,
maps_order: :undefined
}
defp handle_format_spec(%{control_char: char} = spec, opts) when char in 'wWpP' do
+24 -23
View File
@@ -772,12 +772,13 @@ defmodule Logger.TranslatorTest do
end
test "translates Supervisor reports start error" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
children = [worker(__MODULE__, [], function: :error)]
Supervisor.start_link(children, strategy: :one_for_one)
receive do: ({:EXIT, _, {:shutdown, {:failed_to_start_child, _, _}}} -> :ok)
Process.flag(:trap_exit, trap)
assert {:error, {:shutdown, {:failed_to_start_child, __MODULE__, :stop}}} =
Supervisor.start_link(children, strategy: :one_for_one)
end) =~ ~r"""
\[error\] Child Logger.TranslatorTest of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) failed to start
\*\* \(exit\) :stop
@@ -786,12 +787,13 @@ defmodule Logger.TranslatorTest do
end
test "translates Supervisor reports start error with raise" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
children = [worker(__MODULE__, [], function: :undef)]
Supervisor.start_link(children, strategy: :one_for_one)
receive do: ({:EXIT, _, {:shutdown, {:failed_to_start_child, _, _}}} -> :ok)
Process.flag(:trap_exit, trap)
assert {:error, {:shutdown, {:failed_to_start_child, __MODULE__, {:EXIT, _}}}} =
Supervisor.start_link(children, strategy: :one_for_one)
end) =~ ~r"""
\[error\] Child Logger.TranslatorTest of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) failed to start
\*\* \(exit\) an exception was raised:
@@ -804,12 +806,12 @@ defmodule Logger.TranslatorTest do
end
test "translates Supervisor reports terminated" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
children = [worker(Task, [Kernel, :exit, [:stop]])]
{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one, max_restarts: 0)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child Task of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) terminated
\*\* \(exit\) :stop
@@ -827,12 +829,12 @@ defmodule Logger.TranslatorTest do
end
test "translates Supervisor reports max restarts shutdown" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
children = [worker(Task, [Kernel, :exit, [:stop]])]
{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one, max_restarts: 0)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child Task of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) caused shutdown
\*\* \(exit\) :reached_max_restart_intensity
@@ -888,14 +890,14 @@ defmodule Logger.TranslatorTest do
end
test "translates DynamicSupervisor reports abnormal shutdown" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
child = %{id: __MODULE__, start: {__MODULE__, :abnormal, []}}
{:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)
{:ok, _pid2} = DynamicSupervisor.start_child(pid, child)
Process.exit(pid, :normal)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child :undefined of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) shut down abnormally
\*\* \(exit\) :stop
@@ -909,9 +911,9 @@ defmodule Logger.TranslatorTest do
end
test "translates DynamicSupervisor reports abnormal shutdown including extra_arguments" do
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
{:ok, pid} =
DynamicSupervisor.start_link(strategy: :one_for_one, extra_arguments: [:extra])
@@ -919,7 +921,6 @@ defmodule Logger.TranslatorTest do
{:ok, _pid2} = DynamicSupervisor.start_child(pid, child)
Process.exit(pid, :normal)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child :undefined of Supervisor #PID<\d+\.\d+\.\d+> \(Supervisor\.Default\) shut down abnormally
\*\* \(exit\) :stop
@@ -933,14 +934,14 @@ defmodule Logger.TranslatorTest do
end
test "translates named DynamicSupervisor reports abnormal shutdown" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
child = %{id: __MODULE__, start: {__MODULE__, :abnormal, []}}
{:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, name: __MODULE__)
{:ok, _pid2} = DynamicSupervisor.start_child(pid, child)
Process.exit(pid, :normal)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child :undefined of Supervisor Logger.TranslatorTest shut down abnormally
\*\* \(exit\) :stop
@@ -954,11 +955,11 @@ defmodule Logger.TranslatorTest do
end
test "translates :supervisor_bridge progress" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
{:ok, pid} = :supervisor_bridge.start_link(MyBridge, :normal)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[info\] Child of Supervisor #PID<\d+\.\d+\.\d+> \(Logger\.TranslatorTest\.MyBridge\) started
Pid: #PID<\d+\.\d+\.\d+>
@@ -967,11 +968,11 @@ defmodule Logger.TranslatorTest do
end
test "translates :supervisor_bridge reports" do
Process.flag(:trap_exit, true)
assert capture_log(:info, fn ->
trap = Process.flag(:trap_exit, true)
{:ok, pid} = :supervisor_bridge.start_link(MyBridge, :stop)
receive do: ({:EXIT, ^pid, _} -> :ok)
Process.flag(:trap_exit, trap)
end) =~ ~r"""
\[error\] Child of Supervisor #PID<\d+\.\d+\.\d+> \(Logger\.TranslatorTest\.MyBridge\) terminated
\*\* \(exit\) :stop
+45 -15
View File
@@ -107,17 +107,18 @@ defmodule Mix.Compilers.ApplicationTracer do
:ets.delete(table, module)
end
warnings =
{warnings, _} =
:ets.foldl(
fn {module, function, arity, env_module, env_function, env_file, env_line}, acc ->
fn {module, function, arity, env_module, env_function, env_file, env_line},
{acc, cache} ->
# If the module is preloaded, it is always available, so we skip it.
# If the module is non existing, the compiler will warn, so we skip it.
# If the module belongs to this application (from another compiler), we skip it.
# If the module is excluded, we skip it.
with path when is_list(path) <- :code.which(module),
{:ok, module_app} <- app(path),
true <- module_app != app,
false <- module in excludes or {module, function, arity} in excludes do
{module_app, cache} = app_for_module(module, cache)
if module_app != nil and module_app != app and module not in excludes and
{module, function, arity} not in excludes do
env_mfa =
if env_function do
{env_module, elem(env_function, 0), elem(env_function, 1)}
@@ -126,12 +127,12 @@ defmodule Mix.Compilers.ApplicationTracer do
end
warning = {:undefined_app, module_app, module, function, arity}
[{__MODULE__, warning, {env_file, env_line, env_mfa}} | acc]
{[{__MODULE__, warning, {env_file, env_line, env_mfa}} | acc], cache}
else
_ -> acc
{acc, cache}
end
end,
[],
{[], %{}},
table
)
@@ -140,15 +141,44 @@ defmodule Mix.Compilers.ApplicationTracer do
|> Module.ParallelChecker.emit_warnings()
end
# ../elixir/ebin/elixir.beam -> elixir
# ../ssl-9.6/ebin/ssl.beam -> ssl
defp app(path) do
case path |> Path.split() |> Enum.take(-3) do
[dir, "ebin", _beam] -> {:ok, dir |> String.split("-") |> hd()}
_ -> :error
defp app_for_module(module, cache) do
case cache do
%{^module => maybe_app} ->
{maybe_app, cache}
%{} ->
maybe_app = app_for_module(module)
{maybe_app, Map.put(cache, module, maybe_app)}
end
end
# ../elixir/ebin/elixir.beam -> elixir
# ../ssl-9.6/ebin/ssl.beam -> ssl
defp app_for_module(module) do
with [_ | _] = path when is_list(path) <- :code.which(module),
[_ | _] = app <-
path |> Enum.reverse() |> discard_dir() |> discard_ebin() |> collect_dir([]) do
List.to_string(app)
else
_ -> nil
end
end
defp discard_dir([?\\ | path]), do: path
defp discard_dir([?/ | path]), do: path
defp discard_dir([_ | path]), do: discard_dir(path)
defp discard_dir([]), do: []
defp discard_ebin(~c"nibe/" ++ path), do: path
defp discard_ebin(~c"nibe\\" ++ path), do: path
defp discard_ebin(_), do: []
defp collect_dir([?\\ | _], acc), do: acc
defp collect_dir([?/ | _], acc), do: acc
defp collect_dir([?- | path], _acc), do: collect_dir(path, [])
defp collect_dir([head | path], acc), do: collect_dir(path, [head | acc])
defp collect_dir([], acc), do: acc
def stop(pending_save_manifest \\ nil) do
try do
:ets.delete(warnings_table())
+4 -2
View File
@@ -202,7 +202,7 @@ defmodule Mix.Tasks.Format do
args
|> expand_args(dot_formatter, formatter_opts_and_subs, opts)
|> Task.async_stream(&format_file(&1, opts), ordered: false, timeout: 30000)
|> Task.async_stream(&format_file(&1, opts), ordered: false, timeout: :infinity)
|> Enum.reduce({[], []}, &collect_status/2)
|> check!()
end
@@ -551,7 +551,9 @@ defmodule Mix.Tasks.Format do
end
defp stdin_or_wildcard("-"), do: [:stdin]
defp stdin_or_wildcard(path), do: path |> Path.expand() |> Path.wildcard(match_dot: true)
defp stdin_or_wildcard(path),
do: path |> Path.expand() |> Path.wildcard(match_dot: true) |> Enum.filter(&File.regular?/1)
defp elixir_format(content, formatter_opts) do
case Code.format_string!(content, formatter_opts) do
+1
View File
@@ -173,6 +173,7 @@ defmodule Mix.Tasks.Test.Coverage do
if apps_paths = Mix.Project.apps_paths(config) do
build_path = Mix.Project.build_path(config)
apps_paths = Enum.sort(apps_paths)
compile_paths =
Enum.map(apps_paths, fn {app, _} ->
+19 -1
View File
@@ -654,13 +654,31 @@ defmodule Mix.Utils do
headers = [{'user-agent', 'Mix/#{System.version()}'}]
request = {:binary.bin_to_list(path), headers}
# Use the system certificates if available, otherwise skip peer verification
# TODO: Always use system certificates when OTP >= 25.1 is required
ssl_options =
if Code.ensure_loaded?(:httpc) and function_exported?(:httpc, :ssl_verify_host_options, 1) do
try do
apply(:httpc, :ssl_verify_host_options, [true])
rescue
_ ->
Mix.shell().error(
"warning: failed to load system certificates. SSL peer verification will be skipped but downloads are still verified with a checksum"
)
[verify: :verify_none]
end
else
[verify: :verify_none]
end
# We are using relaxed: true because some servers is returning a Location
# header with relative paths, which does not follow the spec. This would
# cause the request to fail with {:error, :no_scheme} unless :relaxed
# is given.
#
# If a proxy environment variable was supplied add a proxy to httpc.
http_options = [relaxed: true] ++ proxy_config(path)
http_options = [relaxed: true, ssl: ssl_options] ++ proxy_config(path)
# Silence the warning from OTP as we verify the contents
level = Logger.level()
+29 -16
View File
@@ -488,6 +488,10 @@ defmodule Mix.DepTest do
Mix.RemoteConverger.register(nil)
end
defp sorted_keys(map) do
map |> Map.keys() |> Enum.sort()
end
test "deps_paths" do
deps = [
{:abc_repo, "0.1.0", path: "custom/abc_repo"},
@@ -502,33 +506,42 @@ defmodule Mix.DepTest do
[:abc_repo, :git_repo, :deps_repo]
]
assert Map.keys(Mix.Project.deps_paths()) == [:abc_repo, :deps_repo, :git_repo]
assert sorted_keys(Mix.Project.deps_paths()) == [:abc_repo, :deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(depth: 1)) == [:abc_repo, :deps_repo]
assert Map.keys(Mix.Project.deps_paths(depth: 2)) == [:abc_repo, :deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(depth: 3)) == [:abc_repo, :deps_repo, :git_repo]
assert sorted_keys(Mix.Project.deps_paths(depth: 1)) == [:abc_repo, :deps_repo]
assert sorted_keys(Mix.Project.deps_paths(depth: 2)) == [:abc_repo, :deps_repo, :git_repo]
assert sorted_keys(Mix.Project.deps_paths(depth: 3)) == [:abc_repo, :deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo])) == [:abc_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:deps_repo])) == [:deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:git_repo])) == [:git_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo])) == [:abc_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 1)) == [:abc_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 1)) == [:deps_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 1)) == [:git_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo])) == [
:deps_repo,
:git_repo
]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 2)) == [:abc_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 2)) == [:git_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo])) == [:git_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 2)) ==
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 1)) == [:abc_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 1)) == [
:deps_repo
]
assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 1)) == [:git_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 2)) == [:abc_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 2)) == [:git_repo]
assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 2)) ==
[:deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo])) ==
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo])) ==
[:abc_repo, :deps_repo, :git_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 1)) ==
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 1)) ==
[:abc_repo, :deps_repo]
assert Map.keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 2)) ==
assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 2)) ==
[:abc_repo, :deps_repo, :git_repo]
end)
end)
+10
View File
@@ -81,6 +81,16 @@ defmodule Mix.Tasks.FormatTest do
end)
end
test "does not try to format a directory that matches a given pattern", context do
in_tmp(context.test, fn ->
File.mkdir_p!("a.ex")
assert_raise Mix.Error, ~r"Could not find a file to format", fn ->
Mix.Tasks.Format.run(["*.ex"])
end
end)
end
test "reads file from stdin and prints to stdout", context do
in_tmp(context.test, fn ->
File.write!("a.ex", """